diff --git a/.gitignore b/.gitignore index 73dc6328..534dcfe3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.pid *.swp *.swo +*package-lock.json node_modules bower_component checkstyle.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 09d318c3..5cd30c56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ This file is created to keep history of the LoopBack SDK Builder, it does not consider or keeps any history of its parent module `loopback-sdk-angular` +## Release 2.1.0-rc.14 + +- Milestone Details: https://github.com/mean-expert-official/loopback-sdk-builder/milestone/48?closed=1 + +- Fix: https://github.com/mean-expert-official/loopback-sdk-builder/issues/515 +- Fix: https://github.com/mean-expert-official/loopback-sdk-builder/issues/514 +- Fix: https://github.com/mean-expert-official/loopback-sdk-builder/issues/511 +- WIP: https://github.com/mean-expert-official/loopback-sdk-builder/issues/495 + ## Release 2.1.0-rc.13.5 - Milestone Details: https://github.com/mean-expert-official/loopback-sdk-builder/milestone/47?closed=1 diff --git a/bin/lb-sdk b/bin/lb-sdk index b12c59d1..19210af7 100755 --- a/bin/lb-sdk +++ b/bin/lb-sdk @@ -23,14 +23,15 @@ var argv = optimist '\nGenerate Client SDK for your LoopBack Application.' + '\nUsage:' + '\n ./node_modules/.bin/lb-sdk server/server app/shared/sdk -d [ng2web | ng2native | ng2universal] -i [enabled | disabled] -v [enabled | strict | disabled]') - .describe('l', 'Client\'s library (angular2, react , ...)') - .describe('d', 'Platform specific drivers (ng2web, ng2native, ng2universal)') + .describe('l', 'Client\'s library (angular, react, vuejs ...)') + .describe('d', 'Platform specific drivers (ng2web, ng2native, ng2universal, react-web)') .describe('i', 'Enable PubSub, IO and FireLoop functionality') .describe('n', 'Enable NGRX functionality (enabled | orm) EXPERIMENTAL FEATURE') .describe('w', 'Automatically wipe SDK Directory') .describe('v', 'Add default values in models') .describe('f', 'Generate only FireLoop SDK + Auth Services') .describe('q', 'quiet mode - no console output (forces -w)') + .describe('t', 'Enable Typescript default true ( React Only )') .default('l', 'angular2') .default('d', 'ng2web') .default('i', 'enabled') @@ -38,7 +39,8 @@ var argv = optimist .default('v', 'disabled') .default('f', 'disabled') .default('q', false) - .alias({ u: 'url', m: 'module-name', l: 'library', i: 'io', n: 'ngrx', d: 'driver', w: 'wipe', v: 'default-values', f: 'fireloop-only', q: 'quiet' }) + .default('t', true) + .alias({ u: 'url', m: 'module-name', l: 'library', i: 'io', n: 'ngrx', d: 'driver', w: 'wipe', v: 'default-values', f: 'fireloop-only', q: 'quiet', t: 'typescript' }) .demand(1) .argv; /** @@ -88,7 +90,6 @@ var appFile = path.resolve(argv._[0]); * Load and Boot LoopBack Application */ var app = require(appFile); - // Default Values var context = { app: app, @@ -102,7 +103,8 @@ var context = { wipe: argv['w'] || 'disabled', defaultValue: argv['v'] || 'disabled', fireloopOnly: argv['f'] || 'disabled', - quiet: argv['q'] || false + quiet: argv['q'] || false, + isTyped: argv['t'] == 'false' ? false : true }; if (context.quiet) { diff --git a/lib/angular2/index.js b/lib/angular2/index.js index dd0d452b..4e98a9d9 100644 --- a/lib/angular2/index.js +++ b/lib/angular2/index.js @@ -724,7 +724,7 @@ module.exports = function generate(ctx) { // the password property anymore but is required for TypeScript purposes if (model.isUser && !model.properties.password) { model.properties.password = { - type: model.properties.username.type + type: String } } // Add Model Properties diff --git a/lib/angular2/shared/config.ejs b/lib/angular2/shared/config.ejs index 40f78127..407258b7 100644 --- a/lib/angular2/shared/config.ejs +++ b/lib/angular2/shared/config.ejs @@ -26,6 +26,7 @@ export class LoopBackConfig { private static debug: boolean = true; private static filterOn: string = 'headers'; private static secure: boolean = false; + private static withCredentials: boolean = false; public static setApiVersion(version: string = 'api'): void { LoopBackConfig.version = version; @@ -82,4 +83,12 @@ export class LoopBackConfig { public static isSecureWebSocketsSet(): boolean { return LoopBackConfig.secure; } + + public static setRequestOptionsCredentials(withCredentials: boolean = false): void { + LoopBackConfig.withCredentials = withCredentials; + } + + public static getRequestOptionsCredentials(): boolean { + return LoopBackConfig.withCredentials; + } } diff --git a/lib/angular2/shared/effects/model.ejs b/lib/angular2/shared/effects/model.ejs index 4ac939ce..4c9fcd9c 100644 --- a/lib/angular2/shared/effects/model.ejs +++ b/lib/angular2/shared/effects/model.ejs @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { <%- modelName %>ActionTypes, <%- modelName %>Actions } from '../actions/<%- modelName %>'; import { LoopbackErrorActions } from '../actions/error'; import { <%- modelName %>Api } from '../services/index'; @@ -57,6 +58,18 @@ export class <%- modelName %>Effects extends BaseLoopbackEffects { resolver({data: response, meta: action.meta}, '<%- model.sharedClass.ctor.relations[rel].targetClass %>', 'deleteByIdSuccess'), of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta)) )) + <% } else if (methodName.match(/(^__link)/) && model.sharedClass.ctor.relations[action.name.split('_').pop()].targetClass) { + var rel = action.name.split('_').pop(); -%> + .mergeMap((response: any) => concat( + of(new actions['<%- model.sharedClass.ctor.relations[rel].modelThrough.definition.name %>Actions'].createSuccess(response, action.meta)), + of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta)) + )) + <% } else if (methodName.match(/(^__unlink)/) && model.sharedClass.ctor.relations[action.name.split('_').pop()].targetClass) { + var rel = action.name.split('_').pop(); -%> + .mergeMap((response: any) => concat( + of(new actions['<%- model.sharedClass.ctor.relations[rel].modelThrough.definition.name %>Actions'].deleteByIdSuccess(response.id, action.meta)), + of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta)) + )) <% } else if (!action.returns || action.returns.length == 0) { -%> .map((response: any) => new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, action.payload.fk, action.meta)) <% } else { -%> diff --git a/lib/angular2/shared/orm/filter.ejs b/lib/angular2/shared/orm/filter.ejs index 94fc0804..7e7b6cfc 100644 --- a/lib/angular2/shared/orm/filter.ejs +++ b/lib/angular2/shared/orm/filter.ejs @@ -2,6 +2,7 @@ import 'rxjs/add/operator/publishReplay'; import 'rxjs/add/operator/combineLatest'; import 'rxjs/add/operator/withLatestFrom'; +import 'rxjs/add/operator/auditTime'; import { Observable } from 'rxjs/Observable'; import * as filterNodes from 'loopback-filters'; diff --git a/lib/angular2/shared/services/core/base.ejs b/lib/angular2/shared/services/core/base.ejs index b1a117a0..295e8479 100644 --- a/lib/angular2/shared/services/core/base.ejs +++ b/lib/angular2/shared/services/core/base.ejs @@ -84,7 +84,7 @@ export abstract class BaseLoopBackApi { if (LoopBackConfig.isHeadersFilteringSet()) { headers.append('filter', JSON.stringify(urlParams.filter)); } else { - filter = `?filter=${ encodeURI(JSON.stringify(urlParams.filter))}`; + filter = `?filter=${ encodeURIComponent(JSON.stringify(urlParams.filter))}`; } delete urlParams.filter; } @@ -104,12 +104,12 @@ export abstract class BaseLoopBackApi { this.searchParams.setJSON(urlParams); let request: Request = new Request( new RequestOptions({ - headers : headers, - method : method, - url : `${url}${filter}`, - search : Object.keys(urlParams).length > 0 - ? this.searchParams.getURLSearchParams() : null, - body : body ? JSON.stringify(body) : undefined + headers : headers, + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 ? this.searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined, + withCredentials: LoopBackConfig.getRequestOptionsCredentials() }) ); return this.http.request(request) diff --git a/lib/helpers/index.js b/lib/helpers/index.js new file mode 100644 index 00000000..fc105a25 --- /dev/null +++ b/lib/helpers/index.js @@ -0,0 +1,762 @@ +const path = require('path'); +const mkdirp = require('mkdirp'); +const rmdir = require('rimraf'); +const fs = require('fs'); +const ejs = require('ejs'); +const builders = { + react: require('./../react/react-builders'), + angular: require('./../react/react-builders') +} +let ctx; + +var _ = require('underscore'); +_.mixin(require('underscore.inflections')); +/** + * EJS Q Filter + * Deprecated in EJS 2 :( + */ +ejs.filters.q = (obj) => JSON.stringify(obj, null, 2); +ejs.filters.pluralize = (text) => _.pluralize(text); +/** + * @author Andres Jimenez + * @license MIT + * @description + * Common Helpers Service for build SDK in Angular and React + * + **/ +/** + * Directory Management + */ + +/** + * @method paramIsContext + * @description + * Testing if the param is a http.context + */ +function paramIsContext(param) { + return (typeof param.http !== 'undefined' && typeof param.http.source !== 'undefined' && param.http.source === 'context'); +} + +/** + * @method paramIsFunction + * @description + * Testing if the param is function type + */ +function paramIsFunction(param) { + return typeof param.http === 'function' +} + +function getModelRelations(model) { + return Object.keys(model.sharedClass.ctor.relations).filter(relationName => + model.sharedClass.ctor.relations[relationName].targetClass && + model.sharedClass.ctor.relations[relationName].targetClass !== model.name + ); +} + +/** + * @method paramIsQuery + * @description + * Testing if the param is a http.query or form + */ +function paramIsQuery(param) { + return ( + ( + typeof param.http === 'undefined' && // Query is default, if http is not defined we treat it as query param + (param.arg && !param.arg.match(/(^id$|fk|^file$|container)/)) // But only if it is not id, fk, file or container + ) + || + ( + typeof param.http !== 'undefined' && typeof param.http.source !== 'undefined' && param.http.source == 'query' + ) + ); +} + +/** + * @method paramIsBody + * @description + * Testing if the param is a http.body or form + */ +function paramIsBody(param) { + return (typeof param.http !== 'undefined' && typeof param.http.source !== 'undefined' && (param.http.source == 'body' ||  param.http.source == 'form')); +} + +/** + * @method paramIsRoute + * @description + * Testing if the param is route type + */ +function paramIsRoute(param) { + return (param.http && param.http.source === 'path') || (param.arg && param.arg.match(/(^id$|fk|^file$|container)/)); +} + +exports.prepareDirectories = (ctx) => { + + ctx.outputFolder = path.resolve(ctx.outputFolder); + + if (!ctx.quiet) { + console.log('Removing base directory %s', ctx.outputFolder); + } + + rmdir.sync(ctx.outputFolder); + // Create required directories + let directories = [ + ctx.outputFolder, + ctx.outputFolder + '/models', + ctx.outputFolder + '/storage', + ctx.outputFolder + '/services/core', + ctx.outputFolder + '/services/custom' + ]; + if (ctx.isIo === 'enabled') directories.push(ctx.outputFolder + '/sockets'); + directories.forEach(directory => mkdirp.sync(directory)); + + if (!ctx.quiet) { + console.log(ctx.driver); + console.log('DRIVER: ', ctx.driver); + } +} + +exports.buildSquema = (ctx) => { + ctx = ctx; + let schema = [ + /** + * SDK INDEXES + */ + { + template: './../templates/shared/index.ejs', + output: `/index.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isIo: ctx.isIo, + framework: ctx.framework, + models: ctx.models, + driver: ctx.driver, + isTyped: ctx.isTyped, + buildModuleImports: builders[ctx.framework].buildModuleImports, + buildNgModuleImports: builders[ctx.framework].buildNgModuleImports, + buildNgProviders: builders[ctx.framework].buildNgProviders, + } + }, + { + template: './../templates/shared/models/index.ejs', + output: `/models/index.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isIo: ctx.isIo, + isTyped: ctx.isTyped, + models: ctx.models + } + }, + { + template: './../templates/shared/services/index.ejs', + output: `/services/index.${ctx.isTyped ? 't' : 'j'}s`, + params: {} + }, + { + template: './../templates/shared/services/custom/index.ejs', + output: `/services/custom/index.${ctx.isTyped ? 't' : 'j'}s`, + params: { models: ctx.models } + }, + { + template: './../templates/shared/services/core/index.ejs', + output: `/services/core/index.${ctx.isTyped ? 't' : 'j'}s`, + params: { isIo: ctx.isIo } + }, + /** + * MODEL LIST SERVICES + */ + { + template: './../templates/shared/services/custom/models.ejs', + output: `/services/custom/SDKModels.${ctx.isTyped ? 't' : 'j'}s`, + params: { + models: ctx.models, + isTyped: ctx.isTyped, + framework: ctx.framework + } + }, + /** + * SDK CONFIG + */ + { + template: './../templates/shared/config.ejs', + output: `/lb.config.${ctx.isTyped ? 't' : 'j'}s`, + params: { + app: ctx.app, + isTyped: ctx.isTyped + } + }, + /** + * SDK STATIC BASE AND CORE FILES + */ + { + template: './../templates/shared/models/base.ejs', + output: `/models/BaseModels.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + loadAccessToken: ctx.loadAccessToken, + // buildServiceDI: ctx.framework === 'react' ? reactBuilder.buildServiceDI : false + } + }, + { + template: './../templates/shared/services/core/auth.ejs', + output: `/services/core/auth.service.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework, + // loadAccessToken: ctx.loadAccessToken + } + }, + { + template: './../templates/shared/services/core/base.ejs', + output: `/services/core/base.service.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isIo: ctx.isIo, + isTyped: ctx.isTyped, + framework: ctx.framework, + buildServiceDI: builders[ctx.framework].buildServiceDI, + buildBaseServiceImports: builders[ctx.framework].buildBaseServiceImports + } + }, + { + template: './../templates/shared/services/core/error.ejs', + output: `/services/core/error.service.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }, + { + template: './../templates/shared/services/core/logger.ejs', + output: `/services/custom/logger.service.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }, + { + template: './../templates/shared/services/core/search.ejs', + output: `/services/core/search.params.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }, + /** + * STORAGE + */ + { + template: './../templates/shared/storage/storage.swaps.ejs', + output: `/storage/storage.swaps.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped + } + } + ]; + // Add Browser Specific Code + if (ctx.driver.match(/ng2web|ng2universal/)) { + schema.push({ + template: './../templates/shared/storage/cookie.browser.ejs', + output: `/storage/cookie.browser.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }); + schema.push({ + template: './../templates/shared/storage/storage.browser.ejs', + output: `/storage/storage.browser.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }); + } + // Add Server Specific Code + if (ctx.driver === 'ng2universal') { + schema.push({ + template: './../templates/shared/storage/cookie.node.ts', + output: `/storage/cookie.node.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }); + } + // Add NativeScript Specific Code + if (ctx.driver === 'ng2native' && ctx.framework !== 'react') { + schema.push({ + template: './../templates/shared/storage/storage.native.ejs', + output: `/storage/storage.native.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + framework: ctx.framework + } + }); + } + /** + * REALTIME MODULE SUPPORT + */ + if (ctx.isIo === 'enabled') { + // Add generic code to any environment + schema = schema.concat([ + { + template: './../templates/shared/sockets/connections.ts', + output: '/sockets/socket.connections.ts', + params: {} + }, + { + template: './../templates/shared/sockets/socket.driver.ts', + output: '/sockets/socket.driver.ts', + params: {} + }, + { + template: './../templates/shared/services/core/io.ejs', + output: '/services/core/io.service.ts', + params: {} + }, + { + template: './../templates/shared/services/core/realtime.ts', + output: '/services/core/real.time.ts', + params: {} + }, + { + template: './../templates/shared/models/fireloop.ejs', + output: '/models/FireLoop.ts', + params: {} + }, + { + template: './../templates/shared/models/flref.ts', + output: '/models/FireLoopRef.ts', + params: {} + } + ]); + // Add Browser Specific Code + if (ctx.driver.match(/ng2web|ng2universal/)) { + schema.push({ + template: './../templates/shared/sockets/socket.browser.ts', + output: '/sockets/socket.browser.ts', + params: {} + }); + } + // Add Server Specific Code + if (ctx.driver === 'ng2universal') { + schema.push({ + template: './../templates/shared/sockets/socket.node.ts', + output: '/sockets/socket.node.ts', + params: {} + }); + } + // Add NativeScript Specific Code + if (ctx.driver === 'ng2native') { + schema.push({ + template: './../templates/shared/sockets/socket.native.ts', + output: '/sockets/socket.native.ts', + params: {} + }); + } + } + /** + * SDK DYNAMIC FILES + */ + Object.keys(ctx.models).forEach(modelName => { + if (ctx.models[modelName].sharedClass.ctor.settings.sdk && + !ctx.models[modelName].sharedClass.ctor.settings.sdk.enabled) { + + if (!ctx.quiet) { + console.warn('LoopBack SDK Builder: %s model was ignored', modelName); + } + + return; + } else { + + if (!ctx.quiet) { + console.info('LoopBack SDK Builder: adding %s model to SDK', modelName); + } + + schema.push( + /** + * SDK MODELS + */ + { + template: './../templates/shared/models/model.ejs', + output: `/models/${modelName}.${ctx.isTyped ? 't' : 'j'}s`, + params: { + isTyped: ctx.isTyped, + model: ctx.models[modelName], + modelName: modelName, + plural: ctx.models[modelName].sharedClass.ctor.settings.plural + || ejs.filters.pluralize(modelName), + path: ctx.models[modelName].sharedClass.ctor.settings.http + && ctx.models[modelName].sharedClass.ctor.settings.http.path + ? ctx.models[modelName].sharedClass.ctor.settings.http.path + : ctx.models[modelName].sharedClass.ctor.settings.plural, + buildPropertyType: buildPropertyType, + buildPropertyDefaultValue: buildPropertyDefaultValue, + buildRelationType: buildRelationType, + buildModelImports, + buildModelProperties + } + } + ); + /** + * SDK CUSTOM SERVICES + */ + if (ctx.fireloopOnly === 'disabled' ||  (ctx.models[modelName].sharedClass.ctor.settings.base === 'User')) { + schema.push({ + template: './../templates/shared/services/custom/service.ejs', + output: `/services/custom/${modelName}.${ctx.isTyped ? 't' : 'j'}s`, + params: { + framework: ctx.framework, + models: ctx.models, + isIo: ctx.isIo, + isTyped: ctx.isTyped, + model: ctx.models[modelName], + modelName: modelName, + moduleName: ctx.moduleName, + loadAccessToken: ctx.loadAccessToken, + buildPostBody, + buildUrlParams, + buildRouteParams, + buildMethodParams: builders[ctx.framework].buildMethodParams, + buildServiceDI: builders[ctx.framework].buildServiceDI, + buildServiceImports: builders[ctx.framework].buildServiceImports, + normalizeMethodName, + buildObservableType, + paramIsContext, + paramIsFunction + } + }); + } + } + }); + /** + * PROCESS SCHEMA + */ + schema.forEach( + config => { + if (!ctx.quiet) { + console.info('Generating: %s', `${ctx.outputFolder}${config.output}`); + } + + fs.writeFileSync( + `${ctx.outputFolder}${config.output}`, + ejs.render(fs.readFileSync( + require.resolve(config.template), + { encoding: 'utf-8' }), + config.params + ) + ) + } + ); + + /** + * @author João Ribeiro , + * @license MIT + * @method buildPropertyType + * @description + * Define which properties should be passed as route params + */ + function buildPropertyType(property) { + if (!property ||  !property.type) { + return 'any'; + } + switch (typeof property.type) { + case 'function': + switch (property.type.name) { + case 'String': + case 'Number': + case 'Boolean': + return property.type.name.toLowerCase(); + case 'Date': + case 'GeoPoint': + return property.type.name; + default: + return 'any'; + } + case 'object': + if (Array.isArray(property.type)) { + return `Array<${buildPropertyType(property.type[0])}>` + } + return 'object'; + default: + return 'any'; + } + } + + /* + * @author Julien Ledun , + * @license MIT + * @method buildPropertyDefaultValue + * @description + * Define defaults null values for class properties + */ + function buildPropertyDefaultValue(property, isTyped) { + let defaultValue = (property.hasOwnProperty('default')) ? property.default : ''; + switch (typeof property.type) { + case 'function': + switch (property.type.name) { + case 'String': + return `'${defaultValue}'`; + case 'Number': + return isNaN(Number(defaultValue)) ? 0 : Number(defaultValue); + case 'Boolean': + return Boolean(defaultValue); + case 'Date': + return isNaN(Date.parse(defaultValue)) ? `new Date(0)` : `new Date('${defaultValue}')`; + case 'GeoPoint': + default: + return isTyped ? "null" : "null"; + } + case 'object': + if (Array.isArray(property.type)) { + return isTyped ? "[]" : "[]"; + } + return isTyped ? "null" : "null"; + default: + return isTyped ? "null" : "null"; + } + } + + /** + * @method buildRelationType + * @description + * Discovers property type according related models that are public + */ + function buildRelationType(model, relationName) { + let relation = model.sharedClass.ctor.relations[relationName]; + let targetClass = relation.targetClass; + let basicType = (ctx.models[targetClass]) ? targetClass : 'any'; + let finalType = relation.type.match(/(hasOne|belongsTo)/g) + ? basicType : `${basicType}[]`; + return finalType; + } + + /** + * @method buildModelImports + * @description + * Define import statement for those model who are related to other scopes + */ + function buildModelImports(model) { + let relations = getModelRelations(model); + let loaded = {}; + let output = []; + if (relations.length > 0) { + relations.forEach((relationName, i) => { + let targetClass = model.sharedClass.ctor.relations[relationName].targetClass; + if (!loaded[targetClass]) { + loaded[targetClass] = true; + output.push(` ${targetClass}`); + } + }); + } + // Add GeoPoint custom type import + Object.keys(model.properties).forEach((property) => { + var geoPointType = buildPropertyType(model.properties[property]); + var hasGeoPointType = geoPointType.indexOf('GeoPoint') !== -1; + if (hasGeoPointType) { + output.push(' GeoPoint'); + } + }); + if (output.length > 0) { + var imports = output.join(',\n'); + output = [ + 'import {', + imports, + '} from \'../index\';\n' + ]; + } + return output.join('\n'); + } + + /** + * @method buildModelProperties + * @description + * Define properties for the given model + */ + function buildModelProperties(model, isInterface, isTyped) { + let output = []; + // Work around to fix a LoopBack update that won't provide + // the password property anymore but is required for TypeScript purposes + if (model.isUser && !model.properties.password) { + model.properties.password = { + type: model.properties.username.type + } + } + // Add Model Properties + Object.keys(model.properties).forEach((propertyName) => { + if (model.isUser && propertyName === 'credentials') return; + let property = model.properties[propertyName]; + let isOptional = isInterface && !property.required ? '?' : ''; + let defaultValue = !isInterface ? ` = ${buildPropertyDefaultValue(property)}` : ''; + defaultValue = ctx.defaultValue !== 'enabled' && ctx.defaultValue !== 'strict' ? '' : defaultValue; + defaultValue = ctx.defaultValue === 'strict' && !property.hasOwnProperty('default') ? '' : defaultValue; + output.push(` "${propertyName}"${isOptional}${isTyped ? ':' + buildPropertyType(property) + { defaultValue } + ';' : ';'}`); + }); + // Add Model Relations + Object.keys(model.sharedClass.ctor.relations).forEach(relation => { + let relationType = buildRelationType(model, relation); + let defaultTypeValue = !isInterface && ctx.defaultValue === 'enabled' && relationType.indexOf('Array') >= 0 ? ' = []' : ''; + defaultTypeValue = !isInterface && ctx.defaultValue === 'enabled' && relationType.indexOf('Array') === -1 ? ' = null' : defaultTypeValue; + output.push(` ${relation}${isInterface ? '?' : ''}${isTyped ? ':' + relationType + defaultTypeValue + ';' : ';'}`); + }); + return output.join('\n'); + } + + function getModelRelations(model) { + return Object.keys(model.sharedClass.ctor.relations).filter(relationName => + model.sharedClass.ctor.relations[relationName].targetClass && + model.sharedClass.ctor.relations[relationName].targetClass !== model.name + ); + } + + function buildPostBody(postData) { + let output = []; + if (Array.isArray(postData)) { + postData = postData.filter(param => { + // Filter out route params and function params + if (paramIsRoute(param) || paramIsFunction(param) ||  paramIsContext(param) ||  paramIsQuery(param)) { + return false + } + // Make sure the param is body or form data + return paramIsBody(param); + }) + if (postData.length > 0) { + output.push(''); + let l = postData.length; + let formData = []; + postData.forEach((property, i) => { + if (property.http.source == 'form') { + formData.push(property); + } else { + output.push(` ${property.arg}: ${property.arg}${(i < l - 1) ? ',' : ''}`); + } + }); + if (formData.length > 0) { + l = formData.length + output.push(` data: {`); + formData.forEach((property, i) => { + output.push(` ${property.arg}: ${property.arg}${(i < l - 1) ? ',' : ''}`); + }) + output.push(` }`); + } + output.push(' '); + } + } + return output.join('\n'); + } + + /** + * @method buildUrlParams + * @description + * Define which properties should be passed using query string + */ + function buildUrlParams(model, methodName, urlParams) { + let output = ['']; + // filter params that should not go over url query string + urlParams = urlParams.filter(param => { + // Filter out route params and function params + if (paramIsRoute(param) || paramIsFunction(param) || paramIsContext(param) || paramIsBody(param)) { + return false + } + // Filter out body params + return paramIsQuery(param); + }); + if (model.isUser && methodName === 'logout') + output.push(` _urlParams.access_token = this.auth.getAccessTokenId();`); + if (urlParams && urlParams.length > 0) { + urlParams.forEach((param, i) => { + output.push(` if (typeof ${param.arg} !== 'undefined' && ${param.arg} !== null) _urlParams.${param.arg} = ${param.arg};`); + }); + } + return output.join('\n'); + } + /** + * @method buildRouteParams + * @description + * Define which properties should be passed as route params + */ + function buildRouteParams(routeParams) { + let output = []; + if (routeParams) { + routeParams = routeParams.filter((param) => { + if (paramIsQuery(param) || paramIsFunction(param) || paramIsContext(param) || paramIsBody(param)) { + return false + } + return paramIsRoute(param) + }); + if (routeParams.length > 0) { + output.push(''); + routeParams.forEach((param, i) => { + output.push(` ${param.arg}: ${param.arg}${(i < routeParams.length - 1) ? ',' : ''}`); + }); + output.push(' '); + } + } + return output.join('\n'); + } + + /** + * @method normalizeMethodName + * @description + * Normalizes method name from loopback form to a more human readable form + */ + function normalizeMethodName(methodName, capitalize) { + return methodName.split('__').map((value, index) => { + return (index < 2 && !capitalize) ? value : (value.charAt(0).toUpperCase() + value.slice(1)); + }).join(''); + } + + /** + * @method buildObservableType + * @description + * Define observable type + */ + function buildObservableType(model, method) { + let type = 'any'; + if ( + method.name.match(/(^createMany$|^find)/g) || + ( + typeof method.returns === 'object' && + (String(method.returns.type).toLowerCase() === 'array' ||  Array.isArray(method.returns.type)) + ) + ) type = `${model.name}[]`; + if (method.name.match(/(^create$|upsert|^findBy|^findOne$)/g)) type = model.name; + return type; + } + + module.exports = { + buildPropertyType, + buildPropertyDefaultValue, + buildRelationType, + buildModelImports, + buildModelProperties, + // getModelRelations, + buildPostBody, + buildUrlParams, + buildRouteParams, + normalizeMethodName, + buildObservableType, + // paramIsContext, + // paramIsFunction + } +} + +/** + * @method buildImportsbuildNgModuleImports + * @description + * Transform an array of objects describing which should be imported into + * the actual template strings + */ +exports.buildImports = (imports) => { + return imports.map(item => + `import ${(item.from ? `{ ${item.module} }` : `'${item.module}'`)}${(item.from ? ` from '${item.from}'` : '')};` + ).join('\n'); +} + +exports.capitalize = (string) => { + return string[0].toUpperCase() + string.slice(1); +} + +module.exports.getModelRelations = getModelRelations; +module.exports.paramIsContext = paramIsContext; +module.exports.paramIsFunction = paramIsFunction; +module.exports.paramIsQuery = paramIsQuery; +module.exports.paramIsBody = paramIsBody; +module.exports.paramIsRoute = paramIsRoute; \ No newline at end of file diff --git a/lib/react/index.js b/lib/react/index.js index 484482e4..6f7f2b15 100644 --- a/lib/react/index.js +++ b/lib/react/index.js @@ -1,3 +1,33 @@ -module.exports = function (ctx) { - console.error('\nLoopBack SDK Builder: REACT Generator is not yet implemented\n'); -}; \ No newline at end of file +/** + * @module React Generator for loopback-sdk-builder + * @author Jonathan Casarrubias <@johncasarrubias> + * @author Andres Jimenez <@ndresdavid> + * @license MIT + * @description + * Defines a SDK Schema and builds according configuration, fork of Angular 2 generator + */ + +var utils = require('../utils'); +var helpers = require('./../helpers'); + +/** + * Generate Client SDK for the given loopback application. + */ +module.exports = function generate(ctx) { + 'use strict'; + // Describe models and remove those blacklisted + ctx.models = utils.describeModels(ctx.app); + /** + * Directory Management + */ + helpers.prepareDirectories(ctx); + /** + * Fix to decide which AcccessToken to get, since usually is private, but not + * Always, so we need to import from the right place + */ + ctx.loadAccessToken = (ctx.models.AccessToken ? false : true); + /** + * LoopBack SDK Builder Schema for Angular 2 and ng2native 2 + **/ + helpers.buildSquema(ctx); +}; diff --git a/lib/react/react-builders.js b/lib/react/react-builders.js new file mode 100644 index 00000000..a8a723df --- /dev/null +++ b/lib/react/react-builders.js @@ -0,0 +1,289 @@ +const helpers = require('./../helpers'); + +exports.buildModuleImports = (models, isIo, driver) => { + let imports = [ + { module: 'JSONSearchParams', from: './services/core/search.params' }, + { module: 'ErrorHandler', from: './services/core/error.service' }, + { module: 'LoopBackAuth', from: './services/core/auth.service' }, + { module: 'LoggerService', from: './services/custom/logger.service' }, + { module: 'SDKModels', from: './services/custom/SDKModels' }, + { module: 'InternalStorage, SDKStorage', from: './storage/storage.swaps' }, + { module: 'HttpModule', from: '@angular/http' }, + { module: 'CommonModule', from: '@angular/common' }, + { module: 'NgModule, ModuleWithProviders', from: '@angular/core' } + ]; + + switch (driver) { + case 'ng2web': + imports.push({ module: 'CookieBrowser', from: './storage/cookie.browser' }); + imports.push({ module: 'StorageBrowser', from: './storage/storage.browser' }); + if (isIo === 'enabled') { + imports.push({ module: 'SocketBrowser', from: './sockets/socket.browser' }); + } + break; + case 'ng2universal': + imports.push({ module: 'CookieBrowser', from: './storage/cookie.browser' }); + imports.push({ module: 'CookieNode', from: './storage/cookie.node' }); + imports.push({ module: 'StorageBrowser', from: './storage/storage.browser' }); + if (isIo === 'enabled') { + imports.push({ module: 'SocketBrowser', from: './sockets/socket.browser' }); + imports.push({ module: 'SocketNode', from: './sockets/socket.node' }); + } + break; + case 'ng2native': + imports.push({ module: 'StorageNative', from: './storage/storage.native' }); + if (isIo === 'enabled') { + imports.push({ module: 'SocketNative', from: './sockets/socket.native' }); + } + break; + } + + + if (isIo === 'enabled') { + imports = imports.concat([ + { module: 'SocketDriver', from: './sockets/socket.driver' }, + { module: 'SocketConnection', from: './sockets/socket.connections' }, + { module: 'RealTime', from: './services/core/real.time' } + ]); + } + + Object.keys(models).forEach(modelName => { + let name = helpers.capitalize(modelName); + imports.push({ module: `${name}Api`, from: `./services/custom/${name}` }); + }); + + return helpers.buildImports(imports); +} + +/** + * @method buildNgProviders + * @description + * Define import statement for the SDK NG Modules + */ +exports.buildNgProviders = (isIo) => { + let imports = ['ErrorHandler']; + if (isIo === 'enabled') { imports.push('SocketConnection'); } + return imports.join(',\n '); +} + +/** + * @method buildServiceDI + * @description + * Define import statement for the SDK NG Modules + */ +exports.buildServiceDI = (isIo) => { + let dependencies = ['@Inject(Http) protected http: Http']; + if (isIo === 'enabled') { + dependencies.push('@Inject(SocketConnection) protected connection: SocketConnection'); + } + dependencies = dependencies.concat([ + '@Inject(SDKModels) protected models: SDKModels', + '@Inject(LoopBackAuth) protected auth: LoopBackAuth', + '@Inject(JSONSearchParams) protected searchParams: JSONSearchParams', + '@Optional() @Inject(ErrorHandler) protected errorHandler: ErrorHandler' + ]) + return dependencies.join(',\n '); +} + +/** + * @method buildBaseServiceImports + * @description + * Define import statement for the SDK Module + **/ +exports.buildBaseServiceImports = (isIo) => { + let imports = [ + { module: 'JSONSearchParams', from: './search.params' }, + { module: 'ErrorHandler', from: './error.service' }, + { module: 'LoopBackAuth', from: './auth.service' }, + { module: 'LoopBackConfig', from: '../../lb.config' }, + { module: 'LoopBackFilter, AccessToken', from: '../../models/BaseModels' }, + { module: 'SDKModels', from: '../custom/SDKModels' }, + { module: 'Observable', from: 'rxjs/Observable' }, + { module: 'Subject', from: 'rxjs/Subject' }, + { module: 'ErrorObservable', from: 'rxjs/observable/ErrorObservable' }, + { module: 'rxjs/add/operator/catch' }, + { module: 'rxjs/add/operator/map' }, + ]; + + if (isIo === 'enabled') { + imports.push({ module: 'SocketConnection', from: '../../sockets/socket.connections' }); + } + + return helpers.buildImports(imports); +} + +/** + * @method buildNgModuleImports + * @description + * Define import statement for the SDK NG Modules + */ +exports.buildNgModuleImports = (models, environment, isIo, driver) => { + let imports = ['LoopBackAuth', 'LoggerService', 'JSONSearchParams', 'SDKModels']; + if (isIo === 'enabled') { imports.push('RealTime'); } + Object.keys(models).forEach(modelName => imports.push(`${helpers.capitalize(modelName)}Api`)); + switch (environment) { + case 'browser': + if (driver === 'ng2web' ||  driver === 'ng2universal') { + imports.push('internalStorageProvider'); + imports.push('{ provide: SDKStorage, useClass: StorageBrowser }'); + if (isIo === 'enabled') { + imports.push('{ provide: SocketDriver, useClass: SocketBrowser }'); + } + } + break; + case 'node': + if (driver === 'ng2universal') { + imports.push('{ provide: InternalStorage, useClass: CookieNode }'); + if (isIo === 'enabled') { + imports.push('{ provide: SocketDriver, useClass: SocketNode }'); + } + } + break; + case 'nativescript': + if (driver === 'ng2native') { + imports.push('{ provide: InternalStorage, useClass: StorageNative }'); + imports.push('{ provide: SDKStorage, useClass: StorageNative }'); + if (isIo === 'enabled') { + imports.push('{ provide: SocketDriver, useClass: SocketNative }'); + } + } + break; + } + return imports.join(',\n '); +} + +/** + * @method buildMethodParams + * @description + * Set which params should be defined for the given remote method + */ +exports.buildMethodParams = (model, methodName, params, isIo, models) => { + //if (model.isUser && methodName === 'logout') return ''; + let output = new Array(); + let relations = helpers.getModelRelations(model); + let availableClasses = relations.map((relationName, index) => + model.sharedClass.ctor.relations[relationName].targetClass + ); + + params = params.filter(param => { + return !helpers.paramIsContext(param) && !helpers.paramIsFunction(param) + }); + + relations.forEach(relationName => { + if (model.sharedClass.ctor.relations[relationName].modelThrough) { + let throughName = helpers.capitalize( + model.sharedClass.ctor.relations[relationName].modelThrough.sharedClass.name + ); + // Only add through models when they are Public + if (models[throughName]) { + availableClasses.push(helpers.capitalize( + model.sharedClass.ctor.relations[relationName].modelThrough.sharedClass.name + )); + } + } + } + ); + if (isIo) params = params.filter(param => !param.arg.match(/(fk|data|options)/)); + params.forEach((param, i, arr) => { + let type, isArray = false; + if (param.type === 'object') { + type = param.arg === 'filter' ? 'LoopBackFilter' : 'any'; + } else { + type = param.type !== 'AccessToken' && param.type !== 'any' + ? helpers.capitalize(param.type) : 'any'; + } + if (!type.match(/(^any$|LoopBackFilter)/) && availableClasses.indexOf(type) < 0) { + type = 'any'; + } + let value = ''; + // Accept Array on createMany method. + if (methodName.match(/createMany/) && param.arg === 'data') { + isArray = true; + } + // Set default value, usually will be {}, but on login we include user + // Should not be undefined or will create request issues + if (!param.required && (model.isUser && methodName === 'login') && param.arg === 'include') { + type = 'any'; + value = " = 'user'"; + } else if (type.match(/(any|LoopBackFilter)/)) { + value = !param.required ? ` = ${isArray ? '[]' : '{}'}` : ''; + } else { + value = !param.required ? ` = ${isArray ? `new Array<${type}>()` : `new ${type}()`}` : ''; + } + output.push(`${param.arg}`); + }); + + // When login, there is a property not coming from LoopBack that is needed. + // so we need to add a rememberMe property to temporal o permanent store the user + if ((model.isUser && methodName === 'login')) { + output.push(`rememberMe = true`); + } + + // When login, there is a property not coming from LoopBack that is needed. + // so we need to add a rememberMe property to temporal o permanent store the user + // UPDATE: it seems it is now coming from loopback, so now is duplicated + /*if ((model.isUser && methodName === 'login')) { + output.push(`rememberMe: boolean = true`); + }*/ + + if (!isIo) { + output.push(`customHeaders`); + } + return output.join(', '); +} + +/** + * @method buildServiceImports + * @description + * Define import statement for those model who are related to other scopes + * IMPORTANT: This method have a very specific flow, changing it may create + * multiple issues on multiple different use cases. + */ +exports.buildServiceImports = (model, loadAccessToken, isIo, models) => { + let modelName = helpers.capitalize(model.name); + let imports = [ + { module: 'SDKModels', from: './SDKModels' }, + { module: 'BaseLoopBackApi', from: '../core/base.service' }, + { module: 'LoopBackConfig', from: '../../lb.config' }, + { + module: `LoopBackFilter, ${model.isUser ? `SDKToken${(loadAccessToken && model.isUser) ? ', AccessToken' : ''}` : ''}`, + from: '../../models/BaseModels' + }, + { module: 'JSONSearchParams', from: '../core/search.params' }, + { module: 'ErrorHandler', from: '../core/error.service' }, + { module: 'Subject', from: 'rxjs/Subject' }, + { module: 'Observable', from: 'rxjs/Rx' }, + { module: modelName, from: `../../models/${modelName}` }, + ]; + if (isIo === 'enabled') { + imports.push({ module: 'SocketConnection', from: '../../sockets/socket.connections' }); + } + let loaded = {}; loaded[model.name] = true; + helpers.getModelRelations(model).forEach((relationName, i) => { + let targetClass = model.sharedClass.ctor.relations[relationName].targetClass; + // It is imperative to check first for through models, else we may miss some + // Through Models. This is because multiple relationships to the same model may have + // different Through models, in the next validation we avoid duplicating models, which + // can lead to miss some through models. + // Finally we will be adding through models only if these are Public + if ( + model.sharedClass.ctor.relations[relationName].modelThrough && + model.sharedClass.ctor.relations[relationName].modelThrough.sharedClass.name !== 'Model' && + models[model.sharedClass.ctor.relations[relationName].modelThrough.sharedClass.name] + ) { + let through = helpers.capitalize(model.sharedClass.ctor.relations[relationName].modelThrough.sharedClass.name); + if (!loaded[through]) { + loaded[through] = true; + imports.push({ module: through, from: `../../models/${through}` }); + } + } + // Now and after the through model was included is the right time to verify if the current model + // was loaded by another relationship, this way we don't duplicate the class during imports' + if (!loaded[targetClass]) { + loaded[targetClass] = true; + imports.push({ module: targetClass, from: `../../models/${targetClass}` }); + } + }); + + return helpers.buildImports(imports); +} \ No newline at end of file diff --git a/lib/templates/shared/config.ejs b/lib/templates/shared/config.ejs new file mode 100644 index 00000000..ce454d22 --- /dev/null +++ b/lib/templates/shared/config.ejs @@ -0,0 +1,152 @@ +<% if (isTyped) { -%>/* tslint:disable */<% } %> +/** +* @module LoopBackConfig +* @description +* +* The LoopBackConfig module help developers to externally +* configure the base url and api version for loopback.io +* +* Example +* +* import { LoopBackConfig } from './sdk'; +* +* @Component() // No metadata needed for this module +* +* export class MyApp { +* constructor() { +* LoopBackConfig.setBaseURL('http://localhost:3000'); +* LoopBackConfig.setApiVersion('api'); +* } +* } +**/ +<% if (isTyped) { -%> +export class LoopBackConfig { + private static path: string = '//<%- app.get('host') %>:<%- app.get('port') %>'; + private static version: string | number = '<%- app.get('restApiRoot').replace(/^\//, '') %>'; + private static authPrefix: string = ''; + private static debug: boolean = true; + private static filterOn: string = 'headers'; + private static secure: boolean = false; + + public static setApiVersion(version: string = 'api'): void { + LoopBackConfig.version = version; + } + + public static getApiVersion(): string | number { + return LoopBackConfig.version; + } + + public static setBaseURL(url: string = '/'): void { + LoopBackConfig.path = url; + } + + public static getPath(): string { + return LoopBackConfig.path; + } + + public static setAuthPrefix(authPrefix: string = ''): void { + LoopBackConfig.authPrefix = authPrefix; + } + + public static getAuthPrefix(): string { + return LoopBackConfig.authPrefix; + } + + public static setDebugMode(isEnabled: boolean): void { + LoopBackConfig.debug = isEnabled; + } + + public static debuggable(): boolean { + return LoopBackConfig.debug; + } + + public static filterOnUrl(): void { + LoopBackConfig.filterOn = 'url'; + } + + public static filterOnHeaders(): void { + LoopBackConfig.filterOn = 'headers'; + } + + public static isHeadersFilteringSet(): boolean { + return (LoopBackConfig.filterOn === 'headers'); + } + + public static setSecureWebSockets(): void { + LoopBackConfig.secure = true; + } + + public static unsetSecureWebSockets(): void { + LoopBackConfig.secure = false; + } + + public static isSecureWebSocketsSet(): boolean { + return LoopBackConfig.secure; + } +} +<% } else { -%> +export class LoopBackConfig { + static path = '//<%- app.get('host') %>:<%- app.get('port') %>'; + static version = '<%- app.get('restApiRoot').replace(/^\//, '') %>'; + static authPrefix = ''; + static debug = true; + static filterOn = 'headers'; + static secure = false; + + static setApiVersion(version = 'api') { + LoopBackConfig.version = version; + } + + static getApiVersion() { + return LoopBackConfig.version; + } + + static setBaseURL(url = '/') { + LoopBackConfig.path = url; + } + + static getPath() { + return LoopBackConfig.path; + } + + static setAuthPrefix(authPrefix = '') { + LoopBackConfig.authPrefix = authPrefix; + } + + static getAuthPrefix() { + return LoopBackConfig.authPrefix; + } + + static setDebugMode(isEnabled) { + LoopBackConfig.debug = isEnabled; + } + + static debuggable() { + return LoopBackConfig.debug; + } + + static filterOnUrl() { + LoopBackConfig.filterOn = 'url'; + } + + static filterOnHeaders() { + LoopBackConfig.filterOn = 'headers'; + } + + static isHeadersFilteringSet() { + return (LoopBackConfig.filterOn === 'headers'); + } + + static setSecureWebSockets() { + LoopBackConfig.secure = true; + } + + static unsetSecureWebSockets() { + LoopBackConfig.secure = false; + } + + static isSecureWebSocketsSet() { + return LoopBackConfig.secure; + } +} +<% } -%> \ No newline at end of file diff --git a/lib/templates/shared/index.ejs b/lib/templates/shared/index.ejs new file mode 100644 index 00000000..b8bffdaa --- /dev/null +++ b/lib/templates/shared/index.ejs @@ -0,0 +1,148 @@ + +/** +* @module SDKModule +* @author Jonathan Casarrubias +* @license MIT 2016 Jonathan Casarrubias +* @version 2.1.0 +* @description +* The SDKModule is a generated Software Development Kit automatically built by +* the LoopBack SDK Builder open source module. +* +* The SDKModule provides Angular 2 >= RC.5 support, which means that NgModules +* can import this Software Development Kit as follows: +* +* +* APP Route Module Context +* ============================================================================ +* import { NgModule } from '@angular/core'; +* import { BrowserModule } from '@angular/platform-browser'; +* // App Root +* import { AppComponent } from './app.component'; +* // Feature Modules +* import { SDK[Browser|Node|Native]Module } from './shared/sdk/sdk.module'; +* // Import Routing +* import { routing } from './app.routing'; +* @NgModule({ +* imports: [ +* BrowserModule, +* routing, +* SDK[Browser|Node|Native]Module.forRoot() +* ], +* declarations: [ AppComponent ], +* bootstrap: [ AppComponent ] +* }) +* export class AppModule { } +* +**/ +<%- (framework === 'angular') ? buildModuleImports(models, isIo, driver): '' %> +<% if (framework === 'react') { -%> +import React, { Component as ReactComponent } from 'react'; +import * as Services from './services'; + +export class Component extends ReactComponent { + models = {}; + constructor(config) { + super(); + config.services.forEach((service) => { + if ( typeof this.services === 'object') this.services = {}; + this[service] = new Services[service](); + }); + } +} +<% } %> +<% if (framework === 'angular') { %> +<% if ( driver === 'ng2web' || driver === 'ng2universal' ) { -%> +/** +* @module SDKBrowserModule +* @description +* This module should be imported when building a Web Application in the following scenarios: +* +* 1.- Regular web application +* 2.- Angular universal application (Browser Portion) +* 3.- Progressive applications (Angular Mobile, Ionic, WebViews, etc) +**/ +@NgModule({ + imports: [ CommonModule, HttpModule ], + declarations: [ ], + exports: [ ], + providers: [ + <%- buildNgProviders(isIo) %> + ] +}) +export class SDKBrowserModule { + static forRoot(internalStorageProvider: any = { + provide: InternalStorage, + useClass: CookieBrowser + }): ModuleWithProviders { + return { + ngModule : SDKBrowserModule, + providers : [ + <%- buildNgModuleImports(models, 'browser', isIo, driver) %> + ] + }; + } +} +<% } -%> +<% if ( driver === 'ng2universal' ) { -%> +/** +* @module SDKNodeModule +* @description +* This module should be imported when building a Angular Universal Application. +**/ +@NgModule({ + imports: [ CommonModule, HttpModule ], + declarations: [ ], + exports: [ ], + providers: [ + <%- buildNgProviders(isIo) %> + ] +}) +export class SDKNodeModule { + static forRoot(): ModuleWithProviders { + return { + ngModule : SDKNodeModule, + providers : [ + <%- buildNgModuleImports(models, 'node', isIo, driver) %> + ] + }; + } +} +<% } -%> +<% if ( driver === 'ng2native' ) { -%> +/** +* @module SDKNativeModule +* @description +* This module should be imported when building a NativeScript Applications. +**/ +@NgModule({ + imports: [ CommonModule, HttpModule ], + declarations: [ ], + exports: [ ], + providers: [ + <%- buildNgProviders(isIo) %> + ] +}) +export class SDKNativeModule { + static forRoot(): ModuleWithProviders { + return { + ngModule : SDKNativeModule, + providers : [ + <%- buildNgModuleImports(models, 'nativescript', isIo, driver) %> + ] + }; + } +} +<% } -%> +<% } %> +/** +* Have Fun!!! +* - Jon +**/ +export * from './models/index'; +export * from './services/index'; +export * from './lb.config'; +<% if ( driver === 'ng2web' ) { -%> +export * from './storage/storage.swaps'; +export { CookieBrowser } from './storage/cookie.browser'; +export { StorageBrowser } from './storage/storage.browser'; +<% } -%> diff --git a/lib/templates/shared/models/base.ejs b/lib/templates/shared/models/base.ejs new file mode 100644 index 00000000..8cb1287f --- /dev/null +++ b/lib/templates/shared/models/base.ejs @@ -0,0 +1,216 @@ +<% if (isTyped) { -%>/* tslint:disable */<% } %> +<% if (!loadAccessToken) { %> +import { AccessToken,<% if (isTyped) { -%> AccessTokenInterface<% } %> } from './AccessToken'; +export * from './AccessToken'; +<% } %> +<% if (isTyped) { -%> +declare var Object: any; +export interface LoopBackFilter { + fields?: any; + include?: any; + limit?: any; + order?: any; + skip?: any; + offset?: any; + where?: any; +} +<% } %> +<% if (loadAccessToken) { -%> +<% if (isTyped) { -%> +export interface AccessTokenInterface { + "id"?: string; + "ttl"?: number; + "scopes"?: ["string"]; + "created"?: Date; + "userId"?: string; + "user"?: any; +} + +export class AccessToken implements AccessTokenInterface { + "id": string; + "ttl": number; + "scopes": ["string"]; + "created": Date; + "userId": string; + "user": any; + constructor(data?: AccessTokenInterface) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `AccessToken`. + */ + public static getModelName() { + return "AccessToken"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of AccessToken for dynamic purposes. + **/ + public static factory(data: AccessTokenInterface): AccessToken{ + return new AccessToken(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + public static getModelDefinition() { + return { + name: 'AccessToken', + plural: 'AccessTokens', + properties: { + "id": { + name: 'id', + type: 'string' + }, + "ttl": { + name: 'ttl', + type: 'number', + default: 1209600 + }, + "scopes": { + name: 'scopes', + type: '["string"]' + }, + "created": { + name: 'created', + type: 'Date' + }, + "userId": { + name: 'userId', + type: 'string' + }, + }, + relations: { + user: { + name: 'user', + type: 'User', + model: 'User' + }, + } + } + } +} + +export class SDKToken implements AccessTokenInterface { + id: any = null; + ttl: number = null; + scopes: any = null; + created: any = null; + userId: any = null; + user: any = null; + rememberMe: boolean = null; + constructor(data?: AccessTokenInterface) { + Object.assign(this, data); + } +} +/** +* This GeoPoint represents both, LoopBack and MongoDB GeoPoint +**/ +export interface GeoPoint { + lat?: number; + lng?: number; + type?: string; + coordinates?: number[]; +} + +export interface StatFilter { + range: string, + custom?: { + start: string, + end: string + }, + where?: {}, + groupBy?: string +} +<% } else { -%> +export class AccessToken { + "id"; + "ttl"; + "scopes"; + "created"; + "userId"; + "user"; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `AccessToken`. + */ + static getModelName() { + return "AccessToken"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of AccessToken for dynamic purposes. + **/ + static factory(data) { + return new AccessToken(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'AccessToken', + plural: 'AccessTokens', + properties: { + "id": { + name: 'id', + type: 'string' + }, + "ttl": { + name: 'ttl', + type: 'number', + default: 1209600 + }, + "scopes": { + name: 'scopes', + type: '["string"]' + }, + "created": { + name: 'created', + type: 'Date' + }, + "userId": { + name: 'userId', + type: 'string' + }, + }, + relations: { + user: { + name: 'user', + type: 'User', + model: 'User' + }, + } + } + } +} + +export class SDKToken { + id = null; + ttl = null; + scopes = null; + created = null; + userId = null; + user = null; + rememberMe = null; + constructor(data) { + Object.assign(this, data); + } +} +<% } %> +<% } %> \ No newline at end of file diff --git a/lib/templates/shared/models/fireloop.ejs b/lib/templates/shared/models/fireloop.ejs new file mode 100644 index 00000000..1883a32b --- /dev/null +++ b/lib/templates/shared/models/fireloop.ejs @@ -0,0 +1,15 @@ +import { FireLoopRef } from './index'; + +export class FireLoop { + + private references: any = {}; + + constructor(private socket: any, private models: { get: Function }) {} + + public ref(model: any): FireLoopRef { + let name: string = model.getModelName(); + model.models = this.models; + this.references[name] = new FireLoopRef(model, this.socket); + return this.references[name]; + } +} diff --git a/lib/templates/shared/models/flref.ts b/lib/templates/shared/models/flref.ts new file mode 100644 index 00000000..4bfd4b28 --- /dev/null +++ b/lib/templates/shared/models/flref.ts @@ -0,0 +1,324 @@ +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { LoopBackFilter, StatFilter } from './index'; +import { SocketConnection } from '../sockets/socket.connections'; +/** + * @class FireLoopRef + * @author Jonathan Casarrubias + * @license MIT + * @description + * This class allows to create FireLoop References which will be in sync with + * Server. It also allows to create FireLoop Reference Childs, that allows to + * persist data according the generic model relationships. + **/ +export class FireLoopRef { + // Reference ID + private id: number = this.buildId(); + // Model Instance (For child references, empty on root references) + private instance: any; + // Model Childs + private childs: any = {}; + // Disposable Events + private disposable: { [key: string]: any } = {}; + /** + * @method constructor + * @param {any} model The model we want to create a reference + * @param {SocketConnection} socket Socket connection to handle events + * @param {FireLoopRef} parent Parent FireLoop model reference + * @param {string} relationship The defined model relationship + * @description + * The constructor will receive the required parameters and then will register this reference + * into the server, needed to allow multiple references for the same model. + * This ids are referenced into this specific client connection and won't have issues + * with other client ids. + **/ + constructor( + private model: any, + private socket: SocketConnection, + private parent: FireLoopRef = null, + private relationship: string = null + ) { + this.socket.emit( + `Subscribe.${!parent ? model.getModelName() : parent.model.getModelName()}`, + { id: this.id, scope: model.getModelName(), relationship: relationship } + ); + return this; + } + /** + * @method dispose + * @return {void} + * @description + * This method is super important to avoid memory leaks in the server. + * This method requires to be called on components destroy + * + * ngOnDestroy() { + * this.someRef.dispose() + * } + **/ + public dispose(): void { + const subscription = this.operation('dispose', {}).subscribe(() => { + Object.keys(this.disposable).forEach((channel: string) => { + this.socket.removeListener(channel, this.disposable[channel]); + this.socket.removeAllListeners(channel); + }); + subscription.unsubscribe(); + }); + } + /** + * @method upsert + * @param {T} data Persisted model instance + * @return {Observable} + * @description + * Operation wrapper for upsert function. + **/ + public upsert(data: T): Observable { + return this.operation('upsert', data); + } + /** + * @method create + * @param {T} data Persisted model instance + * @return {Observable} + * @description + * Operation wrapper for create function. + **/ + public create(data: T): Observable { + return this.operation('create', data); + } + /** + * @method remove + * @param {T} data Persisted model instance + * @return {Observable} + * @description + * Operation wrapper for remove function. + **/ + public remove(data: T): Observable { + return this.operation('remove', data); + } + /** + * @method remote + * @param {string} method Remote method name + * @param {any[]=} params Parameters to be applied into the remote method + * @param {boolean} broadcast Flag to define if the method results should be broadcasted + * @return {Observable} + * @description + * This method calls for any remote method. It is flexible enough to + * allow you call either built-in or custom remote methods. + * + * FireLoop provides this interface to enable calling remote methods + * but also to optionally send any defined accept params that will be + * applied within the server. + **/ + public remote(method: string, params?: any[], broadcast: boolean = false): Observable { + return this.operation('remote', { method, params, broadcast }); + } + /** + * @method onRemote + * @param {string} method Remote method name + * @return {Observable} + * @description + * This method listen for public broadcasted remote method results. If the remote method + * execution is not public only the owner will receive the result data. + **/ + public onRemote(method: string): Observable { + let event: string = 'remote'; + if (!this.relationship) { + event = `${this.model.getModelName()}.${event}`; + } else { + event = `${this.parent.model.getModelName()}.${this.relationship}.${event}`; + } + return this.broadcasts(event, {}); + } + /** + * @method on + * @param {string} event Event name + * @param {LoopBackFilter} filter LoopBack query filter + * @return {Observable} + * @description + * Listener for different type of events. Valid events are: + * - change (Triggers on any model change -create, update, remove-) + * - value (Triggers on new entries) + * - child_added (Triggers when a child is added) + * - child_updated (Triggers when a child is updated) + * - child_removed (Triggers when a child is removed) + **/ + public on(event: string, filter: LoopBackFilter = { limit: 100, order: 'id DESC' }): Observable { + if (event === 'remote') { + throw new Error('The "remote" event is not allowed using "on()" method, use "onRemote()" instead'); + } + let request: any; + if (!this.relationship) { + event = `${this.model.getModelName()}.${event}`; + request = { filter }; + } else { + event = `${this.parent.model.getModelName()}.${this.relationship}.${event}`; + request = { filter, parent: this.parent.instance }; + } + if (event.match(/(value|change|stats)/)) { + return Observable.merge( + this.pull(event, request), + this.broadcasts(event, request) + ); + } else { + return this.broadcasts(event, request); + } + } + /** + * @method stats + * @param {LoopBackFilter=} filter LoopBack query filter + * @return {Observable} + * @description + * Listener for real-time statistics, will trigger on every + * statistic modification. + * TIP: You can improve performance by adding memcached to LoopBack models. + **/ + public stats(filter?: StatFilter): Observable { + return this.on('stats', filter); + } + /** + * @method make + * @param {any} instance Persisted model instance reference + * @return {Observable} + * @description + * This method will set a model instance into this a new FireLoop Reference. + * This allows to persiste parentship when creating related instances. + * + * It also allows to have multiple different persisted instance references to same model. + * otherwise if using singleton will replace a previous instance for a new instance, when + * we actually want to have more than 1 instance of same model. + **/ + public make(instance: any): FireLoopRef { + let reference: FireLoopRef = new FireLoopRef(this.model, this.socket); + reference.instance = instance; + return reference; + } + /** + * @method child + * @param {string} relationship A defined model relationship + * @return {FireLoopRef} + * @description + * This method creates child references, which will persist related model + * instances. e.g. Room.messages, where messages belongs to a specific Room. + **/ + public child(relationship: string): FireLoopRef { + // Return singleton instance + if (this.childs[relationship]) { return this.childs[relationship]; } + // Try to get relation settings from current model + let settings: any = this.model.getModelDefinition().relations[relationship]; + // Verify the relationship actually exists + if (!settings) { + throw new Error(`Invalid model relationship ${this.model.getModelName()} <-> ${relationship}, verify your model settings.`); + } + // Verify if the relationship model is public + if (settings.model === '') { + throw new Error(`Relationship model is private, cam't use ${relationship} unless you set your model as public.`); + } + // Lets get a model reference and add a reference for all of the models + let model: any = this.model.models.get(settings.model); + model.models = this.model.models; + // If everything goes well, we will store a child reference and return it. + this.childs[relationship] = new FireLoopRef(model, this.socket, this, relationship); + return this.childs[relationship]; + } + /** + * @method pull + * @param {string} event Event name + * @param {any} request Type of request, can be LB-only filter or FL+LB filter + * @return {Observable} + * @description + * This method will pull initial data from server + **/ + private pull(event: string, request: any): Observable { + let sbj: Subject = new Subject(); + let that: FireLoopRef = this; + let nowEvent: any = `${event}.pull.requested.${this.id}`; + this.socket.emit(`${event}.pull.request.${this.id}`, request); + function pullNow(data: any) { + if (that.socket.removeListener) { + that.socket.removeListener(nowEvent, pullNow); + } + sbj.next(data); + }; + this.socket.on(nowEvent, pullNow); + return sbj.asObservable(); + } + /** + * @method broadcasts + * @param {string} event Event name + * @param {any} request Type of request, can be LB-only filter or FL+LB filter + * @return {Observable} + * @description + * This will listen for public broadcasts announces and then request + * for data according a specific client request, not shared with other clients. + **/ + private broadcasts(event: string, request: any): Observable { + let sbj: Subject = new Subject(); + let channels: { announce: string, broadcast: string } = { + announce: `${event}.broadcast.announce.${this.id}`, + broadcast: `${event}.broadcast.${this.id}` + }; + let that = this; + // Announces Handler + this.disposable[channels.announce] = function (res: T) { + that.socket.emit(`${event}.broadcast.request.${that.id}`, request) + }; + // Broadcasts Handler + this.disposable[channels.broadcast] = function (data: any) { + sbj.next(data); + }; + this.socket.on(channels.announce, this.disposable[channels.announce]); + this.socket.on(channels.broadcast, this.disposable[channels.broadcast]); + return sbj.asObservable(); + } + /** + * @method operation + * @param {string} event Event name + * @param {any} data Any type of data sent to the server + * @return {Observable} + * @description + * This internal method will run operations depending on current context + **/ + private operation(event: string, data: any): Observable { + if (!this.relationship) { + event = `${this.model.getModelName()}.${event}.${this.id}`; + } else { + event = `${this.parent.model.getModelName()}.${this.relationship}.${event}.${this.id}`; + } + let subject: Subject = new Subject(); + let config: { data: any, parent: any } = { + data, + parent: this.parent && this.parent.instance ? this.parent.instance : null + }; + this.socket.emit(event, config); + let resultEvent: string = ''; + if (!this.relationship) { + resultEvent = `${this.model.getModelName()}.value.result.${this.id}`; + } else { + resultEvent = `${this.parent.model.getModelName()}.${this.relationship}.value.result.${this.id}`; + } + this.socket.on(resultEvent, (res: any) => { + if (res.error) { + subject.error(res); + } else { + subject.next(res); + } + }); + if (event.match('dispose')) { + setTimeout(() => subject.next()); + } + // This event listener will be wiped within socket.connections + this.socket.sharedObservables.sharedOnDisconnect.subscribe(() => subject.complete()); + return subject.asObservable().catch((error: any) => Observable.throw(error)); + } + /** + * @method buildId + * @return {number} + * @description + * This internal method build an ID for this reference, this allows to have + * multiple references for the same model or relationships. + **/ + private buildId(): number { + return Date.now() + Math.floor(Math.random() * 100800) * + Math.floor(Math.random() * 100700) * + Math.floor(Math.random() * 198500); + } +} diff --git a/lib/templates/shared/models/index.ejs b/lib/templates/shared/models/index.ejs new file mode 100644 index 00000000..637f76d8 --- /dev/null +++ b/lib/templates/shared/models/index.ejs @@ -0,0 +1,13 @@ +/* tslint:disable */ +<% for (var modelName in models) { + var meta = models[modelName]; + // capitalize the model name + modelName = modelName[0].toUpperCase() + modelName.slice(1); +-%> +export * from './<%- modelName %>'; +<% } // for modelName in models -%> +export * from './BaseModels'; +<% if ( isIo === 'enabled' ){ -%>export * from './FireLoopRef'; +<% } +-%> + diff --git a/lib/templates/shared/models/model.ejs b/lib/templates/shared/models/model.ejs new file mode 100644 index 00000000..c6fd607f --- /dev/null +++ b/lib/templates/shared/models/model.ejs @@ -0,0 +1,112 @@ +<% if (isTyped) { -%>/* tslint:disable */ +<%- buildModelImports(model) %> +declare var Object: any; +export interface <%- modelName %>Interface { +<%- buildModelProperties(model, true) %> +} + +export class <%- modelName %> implements <%- modelName %>Interface { +<%- buildModelProperties(model) %> + constructor(data?: <%- modelName %>Interface) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `<%- modelName %>`. + */ + public static getModelName() { + return <%-: modelName | q %>; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of <%- modelName %> for dynamic purposes. + **/ + public static factory(data: <%- modelName %>Interface): <%- modelName %>{ + return new <%- modelName %>(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + public static getModelDefinition() { + return { + name: '<%- modelName %>', + plural: '<%- plural %>', + path: '<%- path || plural %>', + properties: {<% for ( var prop in model.properties ) { %> + "<%= prop %>": { + name: '<%= prop %>', + type: '<%= buildPropertyType( model.properties[prop] ) %>'<% if ( model.properties[prop].hasOwnProperty( "default" ) ) { %>, + default: <%- buildPropertyDefaultValue( model.properties[prop] ) %><% } %> + },<% } %> + }, + relations: {<% for ( var rel in model.sharedClass.ctor.relations ) { %> + <%= rel %>: { + name: '<%= rel %>', + type: '<%- buildRelationType( model, rel ) %>', + model: '<%- model.sharedClass.ctor.relations[rel].targetClass %>' + },<% } %> + } + } + } +} +<% } else { -%> + +<%- buildModelImports(model) %> + +export class <%- modelName %> { +<%- buildModelProperties(model, false, isTyped) %> + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `<%- modelName %>`. + */ + static getModelName() { + return <%-: modelName | q %>; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of <%- modelName %> for dynamic purposes. + **/ + static factory(data) { + return new <%- modelName %>(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: '<%- modelName %>', + plural: '<%- plural %>', + path: '<%- path || plural %>', + properties: {<% for ( var prop in model.properties ) { %> + "<%= prop %>": { + name: '<%= prop %>', + type: '<%= buildPropertyType( model.properties[prop] ) %>'<% if ( model.properties[prop].hasOwnProperty( "default" ) ) { %>, + default: <%- buildPropertyDefaultValue( model.properties[prop] ) %><% } %> + },<% } %> + }, + relations: {<% for ( var rel in model.sharedClass.ctor.relations ) { %> + <%= rel %>: { + name: '<%= rel %>', + type: '<%- buildRelationType( model, rel ) %>', + model: '<%- model.sharedClass.ctor.relations[rel].targetClass %>' + },<% } %> + } + } + } +} +<% } %> \ No newline at end of file diff --git a/lib/templates/shared/services/core/auth.ejs b/lib/templates/shared/services/core/auth.ejs new file mode 100644 index 00000000..23a28bfa --- /dev/null +++ b/lib/templates/shared/services/core/auth.ejs @@ -0,0 +1,329 @@ +<% if (isTyped) { -%>/* tslint:disable */ +declare var Object: any; +<% } %> +<% if (framework === 'angular') { %> +import { Injectable, Inject } from '@angular/core'; +<% } %> +import { InternalStorage } from '../../storage/storage.swaps'; +import { SDKToken } from '../../models/BaseModels'; +/** +* @author Jonathan Casarrubias +* @module SocketConnection +* @license MIT +* @description +* This module handle socket connections and return singleton instances for each +* connection, it will use the SDK Socket Driver Available currently supporting +* Angular 2 for web, NativeScript 2 and Angular Universal. +**/ +<% if (framework === 'angular') { %> +@Injectable() +<% } %> +export class LoopBackAuth { +<% if (isTyped) { -%> + /** + * @type {SDKToken} + **/ + private token: SDKToken = new SDKToken(); + /** + * @type {string} + **/ + protected prefix: string = '$LoopBackSDK$'; + /** + * @method constructor + * @param {InternalStorage} storage Internal Storage Driver + * @description + * The constructor will initialize the token loading data from storage + **/ + constructor(<% if (framework === 'angular') { -%>@Inject(InternalStorage) protected storage: InternalStorage<% } %>) { + + <% if (framework === 'react') { -%> + this.storage = new InternalStorage(); + <% } %> + this.token.id = this.load('id'); + this.token.user = this.load('user'); + this.token.userId = this.load('userId'); + this.token.created = this.load('created'); + this.token.ttl = this.load('ttl'); + this.token.rememberMe = this.load('rememberMe'); + } + /** + * @method setRememberMe + * @param {boolean} value Flag to remember credentials + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials + **/ + public setRememberMe(value: boolean): void { + this.token.rememberMe = value; + } + /** + * @method setUser + * @param {any} user Any type of user model + * @return {void} + * @description + * This method will update the user information and persist it if the + * rememberMe flag is set. + **/ + public setUser(user: any) { + this.token.user = user; + this.save(); + } + /** + * @method setToken + * @param {SDKToken} token SDKToken or casted AccessToken instance + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials + **/ + public setToken(token: SDKToken): void { + this.token = Object.assign(this.token, token); + this.save(); + } + /** + * @method getToken + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials. + **/ + public getToken(): SDKToken { + return this.token; + } + /** + * @method getAccessTokenId + * @return {string} + * @description + * This method will return the actual token string, not the object instance. + **/ + public getAccessTokenId(): string { + return this.token.id; + } + /** + * @method getCurrentUserId + * @return {any} + * @description + * This method will return the current user id, it can be number or string. + **/ + public getCurrentUserId(): any { + return this.token.userId; + } + /** + * @method getCurrentUserData + * @return {any} + * @description + * This method will return the current user instance. + **/ + public getCurrentUserData(): any { + return (typeof this.token.user === 'string') ? JSON.parse(this.token.user) : this.token.user; + } + /** + * @method save + * @return {boolean} Whether or not the information was saved + * @description + * This method will save in either local storage or cookies the current credentials. + * But only if rememberMe is enabled. + **/ + public save(): boolean { + if (this.token.rememberMe) { + this.persist('id', this.token.id); + this.persist('user', this.token.user); + this.persist('userId', this.token.userId); + this.persist('created', this.token.created); + this.persist('ttl', this.token.ttl); + this.persist('rememberMe', this.token.rememberMe); + return true; + } else { + return false; + } + }; + /** + * @method load + * @param {string} prop Property name + * @return {any} Any information persisted in storage + * @description + * This method will load either from local storage or cookies the provided property. + **/ + protected load(prop: string): any { + return this.storage.get(`${this.prefix}${prop}`); + } + /** + * @method clear + * @return {void} + * @description + * This method will clear cookies or the local storage. + **/ + public clear(): void { + Object.keys(this.token).forEach((prop: string) => this.storage.remove(`${this.prefix}${prop}`)); + this.token = new SDKToken(); + } + /** + * @method persist + * @return {void} + * @description + * This method saves values to storage + **/ + protected persist(prop: string, value: any): void { + try { + this.storage.set( + `${this.prefix}${prop}`, + (typeof value === 'object') ? JSON.stringify(value) : value + ); + } + catch (err) { + console.error('Cannot access local/session storage:', err); + } + } +<% } else { -%> + /** + * @type {SDKToken} + **/ + token = new SDKToken(); + /** + * @type {string} + **/ + prefix = '$LoopBackSDK$'; + /** + * @method constructor + * @param {InternalStorage} storage Internal Storage Driver + * @description + * The constructor will initialize the token loading data from storage + **/ + constructor(<% if (framework === 'angular') { -%>@Inject(InternalStorage) protected storage: InternalStorage<% } %>) { + +<% if (framework === 'react') { -%> + this.storage = new InternalStorage(); +<% } %> + this.token.id = this.load('id'); + this.token.user = this.load('user'); + this.token.userId = this.load('userId'); + this.token.created = this.load('created'); + this.token.ttl = this.load('ttl'); + this.token.rememberMe = this.load('rememberMe'); + } + /** + * @method setRememberMe + * @param {boolean} value Flag to remember credentials + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials + **/ + setRememberMe(value) { + this.token.rememberMe = value; + } + /** + * @method setUser + * @param {any} user Any type of user model + * @return {void} + * @description + * This method will update the user information and persist it if the + * rememberMe flag is set. + **/ + setUser(user) { + this.token.user = user; + this.save(); + } + /** + * @method setToken + * @param {SDKToken} token SDKToken or casted AccessToken instance + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials + **/ + setToken(token) { + this.token = Object.assign(this.token, token); + this.save(); + } + /** + * @method getToken + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials. + **/ + getToken() { + return this.token; + } + /** + * @method getAccessTokenId + * @return {string} + * @description + * This method will return the actual token string, not the object instance. + **/ + getAccessTokenId() { + return this.token.id; + } + /** + * @method getCurrentUserId + * @return {any} + * @description + * This method will return the current user id, it can be number or string. + **/ + getCurrentUserId() { + return this.token.userId; + } + /** + * @method getCurrentUserData + * @return {any} + * @description + * This method will return the current user instance. + **/ + getCurrentUserData() { + return (typeof this.token.user === 'string') ? JSON.parse(this.token.user) : this.token.user; + } + /** + * @method save + * @return {boolean} Whether or not the information was saved + * @description + * This method will save in either local storage or cookies the current credentials. + * But only if rememberMe is enabled. + **/ + save() { + if (this.token.rememberMe) { + this.persist('id', this.token.id); + this.persist('user', this.token.user); + this.persist('userId', this.token.userId); + this.persist('created', this.token.created); + this.persist('ttl', this.token.ttl); + this.persist('rememberMe', this.token.rememberMe); + return true; + } else { + return false; + } + }; + /** + * @method load + * @param {string} prop Property name + * @return {any} Any information persisted in storage + * @description + * This method will load either from local storage or cookies the provided property. + **/ + load(prop) { + return this.storage.get(`${this.prefix}${prop}`); + } + /** + * @method clear + * @return {void} + * @description + * This method will clear cookies or the local storage. + **/ + clear() { + Object.keys(this.token).forEach((prop) => this.storage.remove(`${this.prefix}${prop}`)); + this.token = new SDKToken(); + } + /** + * @method persist + * @return {void} + * @description + * This method saves values to storage + **/ + persist(prop, value) { + try { + this.storage.set( + `${this.prefix}${prop}`, + (typeof value === 'object') ? JSON.stringify(value) : value + ); + } + catch (err) { + console.error('Cannot access local/session storage:', err); + } + } +<% } %> +} diff --git a/lib/templates/shared/services/core/base.ejs b/lib/templates/shared/services/core/base.ejs new file mode 100644 index 00000000..c8c25f91 --- /dev/null +++ b/lib/templates/shared/services/core/base.ejs @@ -0,0 +1,1345 @@ +<% if (isTyped) { -%>/* tslint:disable */ +<%- buildBaseServiceImports(isIo) %> +// Making Sure EventSource Type is available to avoid compilation issues. +declare var EventSource: any; +<% if (framework === 'react') { %> +import axios from 'axios'; +import 'rxjs/add/observable/fromPromise'; +<% } %> +/** +* @module BaseLoopBackApi +* @author Jonathan Casarrubias <@johncasarrubias> +* @author Nikolay Matiushenkov +* @license MIT +* @description +* Abstract class that will be implemented in every custom service automatically built +* by the sdk builder. +* It provides the core functionallity for every API call, either by HTTP Calls or by +* WebSockets. +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +<% if (framework === 'react') { %> + let instance = null; +<% } %> +export abstract class BaseLoopBackApi { + + protected path: string; + protected model: any; +<% if (framework === 'react') { -%> + models: any; + auth: any; +<% } %> + constructor( + <%- (framework === 'angular') ? buildServiceDI(isIo) : '' %> + ) { +<% if (framework === 'react') { -%> + this.models = new SDKModels(); + this.model = this.models.get(this.getModelName()); + this.auth = new LoopBackAuth(); + if (instance) { + return instance; + } + instance = this; +<% } %> +<% if (framework === 'angular') { -%> + this.model = this.models.get(this.getModelName()); +<% } %> + } + /** + * @method request + * @param {string} method Request method (GET, POST, PUT) + * @param {string} url Request url (my-host/my-url/:id) + * @param {any} routeParams Values of url parameters + * @param {any} urlParams Parameters for building url (filter and other) + * @param {any} postBody Request postBody + * @return {Observable} + * @description + * This is a core method, every HTTP Call will be done from here, every API Service will + * extend this class and use this method to get RESTful communication. + **/ + public request( + method : string, + url : string, + routeParams : any = {}, + urlParams : any = {}, + postBody : any = {}, + pubsub : boolean = false, + customHeaders? : Function + ): Observable { + // Transpile route variables to the actual request Values + Object.keys(routeParams).forEach((key: string) => { + url = url.replace(new RegExp(":" + key + "(\/|$)", "g"), routeParams[key] + "$1") + }); + if (pubsub) { +<% if ( isIo === 'enabled' ){ -%> + if (url.match(/fk/)) { + let arr = url.split('/'); arr.pop(); + url = arr.join('/'); + } + let event: string = (`[${method}]${url}`).replace(/\?/, ''); + let subject: Subject = new Subject(); + this.connection.on(event, (res: any) => subject.next(res)); + return subject.asObservable(); +<% } else { -%> + console.info('SDK: PubSub functionality is disabled, generate SDK using -io enabled'); +<% } -%> + } else { + // Headers to be sent +<% if ( framework === 'angular') { -%> + let headers = new Headers(); + headers.append('Content-Type', 'application/json'); +<% } %> +<% if ( framework === 'react') { -%> + +let headers = { + 'Content-Type': 'application/json' + }; +<% } %> + // Authenticate request + this.authenticate(url, headers); + // Body fix for built in remote methods using "data", "options" or "credentials + // that are the actual body, Custom remote method properties are different and need + // to be wrapped into a body object + let body: any; + let postBodyKeys = typeof postBody === 'object' ? Object.keys(postBody) : [] + if (postBodyKeys.length === 1) { + body = postBody[postBodyKeys.shift()]; + } else { + body = postBody; + } + let filter: string = ''; + // Separate filter object from url params and add to search query + if (urlParams.filter) { + if (LoopBackConfig.isHeadersFilteringSet()) { +<% if ( framework === 'angular') { -%> + headers.append('filter', JSON.stringify(urlParams.filter)); +<% } %> +<% if ( framework === 'react') { -%> + headers.filter = JSON.stringify(urlParams.filter); +<% } %> + } else { + filter = `?filter=${ encodeURI(JSON.stringify(urlParams.filter))}`; + } + delete urlParams.filter; + } + // Separate where object from url params and add to search query + /** + CODE BELOW WILL GENERATE THE FOLLOWING ISSUES: + - https://github.com/mean-expert-official/loopback-sdk-builder/issues/356 + - https://github.com/mean-expert-official/loopback-sdk-builder/issues/328 + if (urlParams.where) { + headers.append('where', JSON.stringify(urlParams.where)); + delete urlParams.where; + } + **/ + if (typeof customHeaders === 'function') { + headers = customHeaders(headers); + } +<% if (framework === 'angular') { -%> + this.searchParams.setJSON(urlParams); + let request = new Request( + new RequestOptions({ + headers : headers, + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 + ? this.searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined + }) + ); + return this.http.request(request) + .map((res) => (res.text() != "" ? res.json() : {})) + .catch((e) => this.errorHandler.handleError(e)); +<% } %> +<% if (framework === 'react') { -%> + let searchParams = new JSONSearchParams(); + let errorHandler = new ErrorHandler(); + searchParams.setJSON(urlParams); + let request = new axios.request({ + headers , + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 + ? searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined + } + ); + return Observable.fromPromise(request) + .map((res) => res.data) + .catch((e) => errorHandler.handleError(e)); +<% } %> + } + } + /** + * @method authenticate + * @author Jonathan Casarrubias + * @license MIT + * @param {string} url Server URL + * @param {Headers} headers HTTP Headers + * @return {void} + * @description + * This method will try to authenticate using either an access_token or basic http auth + */ + public authenticate(url: string, headers: Headers): void { + if (this.auth.getAccessTokenId()) { +<% if ( framework === 'angular') { -%> + headers.append( + 'Authorization', + LoopBackConfig.getAuthPrefix() + this.auth.getAccessTokenId() + ); +<% } %> +<% if ( framework === 'react') { -%> + headers.Authorization = LoopBackConfig.getAuthPrefix() + this.auth.getAccessTokenId(); +<% } %> + } + } + /** + * @method create + * @author Jonathan Casarrubias + * @license MIT + * @param {T} data Generic data type + * @return {Observable} + * @description + * Generic create method + */ + public create(data: T, customHeaders?: Function): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, null, customHeaders).map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onCreate + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic pubsub oncreate many method + */ + public onCreate(data: T[]): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, true) + .map((datum: T[]) => datum.map((data: T) => this.model.factory(data))); + } +<% } -%> + /** + * @method createMany + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic create many method + */ + public createMany(data: T[], customHeaders?: Function): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((datum: T[]) => datum.map((data: T) => this.model.factory(data))); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onCreateMany + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic create many method + */ + public onCreateMany(data: T[]): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, true) + .map((datum: T[]) => datum.map((data: T) => this.model.factory(data))); + } +<% } -%> + /** + * @method findById + * @author Jonathan Casarrubias + * @license MIT + * @param {any} data Generic data type + * @return {Observable} + * @description + * Generic findById method + */ + public findById(id: any, filter: LoopBackFilter = {}, customHeaders?: Function): Observable { + let _urlParams: any = {}; + if (filter) _urlParams.filter = filter; + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, _urlParams, undefined, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } + /** + * @method find + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic find method + */ + public find(filter: LoopBackFilter = {}, customHeaders?: Function): Observable { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, { filter }, undefined, null, customHeaders) + .map((datum: T[]) => datum.map((data: T) => this.model.factory(data))); + } + /** + * @method exists + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic exists method + */ + public exists(id: any, customHeaders?: Function): Observable { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id/exists' + ].join('/'), { id }, undefined, undefined, null, customHeaders); + } + /** + * @method findOne + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic findOne method + */ + public findOne(filter: LoopBackFilter = {}, customHeaders?: Function): Observable { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'findOne' + ].join('/'), undefined, { filter }, undefined, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } + /** + * @method updateAll + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic updateAll method + */ + public updateAll(where: any = {}, data: T, customHeaders?: Function): Observable<{ count: 'number' }> { + let _urlParams: any = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'update' + ].join('/'), undefined, _urlParams, { data }, null, customHeaders); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpdateAll + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpdateAll method + */ + public onUpdateAll(where: any = {}, data: T): Observable<{ count: 'number' }> { + let _urlParams: any = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'update' + ].join('/'), undefined, _urlParams, { data }, true); + } +<% } -%> + /** + * @method deleteById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic deleteById method + */ + public deleteById(id: any, customHeaders?: Function): Observable { + return this.request('DELETE', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, undefined, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onDeleteById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onDeleteById method + */ + public onDeleteById(id: any): Observable { + return this.request('DELETE', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, undefined, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method count + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable<{ count: number }>} + * @description + * Generic count method + */ + public count(where: any = {}, customHeaders?: Function): Observable<{ count: number }> { + let _urlParams: any = {}; + if (where) _urlParams.where = where; + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'count' + ].join('/'), undefined, _urlParams, undefined, null, customHeaders); + } + /** + * @method updateAttributes + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic updateAttributes method + */ + public updateAttributes(id: any, data: T, customHeaders?: Function): Observable { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, { data }, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpdateAttributes + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic onUpdateAttributes method + */ + public onUpdateAttributes(id: any, data: T): Observable { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, { data }, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method upsert + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsert method + */ + public upsert(data: any = {}, customHeaders?: Function): Observable { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpsert + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpsert method + */ + public onUpsert(data: any = {}): Observable { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method upsertPatch + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsert method using patch http method + */ + public upsertPatch(data: any = {}, customHeaders?: Function): Observable { + return this.request('PATCH', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpsertPatch + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpsertPatch method using patch http method + */ + public onUpsertPatch(data: any = {}): Observable { + return this.request('PATCH', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method upsertWithWhere + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsertWithWhere method + */ + public upsertWithWhere(where: any = {}, data: any = {}, customHeaders?: Function): Observable { + let _urlParams: any = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'upsertWithWhere' + ].join('/'), undefined, _urlParams, { data }, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpsertWithWhere + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpsertWithWhere method + */ + public onUpsertWithWhere(where: any = {}, data: any = {}): Observable { + let _urlParams: any = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'upsertWithWhere' + ].join('/'), undefined, _urlParams, { data }, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method replaceOrCreate + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic replaceOrCreate method + */ + public replaceOrCreate(data: any = {}, customHeaders?: Function): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'replaceOrCreate' + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onReplaceOrCreate + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic onReplaceOrCreate method + */ + public onReplaceOrCreate(data: any = {}): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'replaceOrCreate' + ].join('/'), undefined, undefined, { data }, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method replaceById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic replaceById method + */ + public replaceById(id: any, data: any = {}, customHeaders?: Function): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id', 'replace' + ].join('/'), { id }, undefined, { data }, null, customHeaders) + .map((data: T) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onReplaceById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic onReplaceById method + */ + public onReplaceById(id: any, data: any = {}): Observable { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id', 'replace' + ].join('/'), { id }, undefined, { data }, true).map((data: T) => this.model.factory(data)); + } +<% } -%> + /** + * @method createChangeStream + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic createChangeStream method + */ + public createChangeStream(): Observable { + let subject = new Subject(); + if (typeof EventSource !== 'undefined') { + let emit = (msg: any) => subject.next(JSON.parse(msg.data)); + var source = new EventSource([ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'change-stream' + ].join('/')); + source.addEventListener('data', emit); + source.onerror = emit; + } else { + console.warn('SDK Builder: EventSource is not supported'); + } + return subject.asObservable(); + } + /** + * @method getModelName + * @author Jonathan Casarrubias + * @license MIT + * @return {string} + * @description + * Abstract getModelName method + */ + abstract getModelName(): string; +} +<% } else { -%> +<%- buildBaseServiceImports(isIo) %> +<% if (framework === 'react') { %> +import axios from 'axios'; +import 'rxjs/add/observable/fromPromise'; +<% } %> +/** +* @module BaseLoopBackApi +* @author Jonathan Casarrubias <@johncasarrubias> +* @author Nikolay Matiushenkov +* @license MIT +* @description +* Abstract class that will be implemented in every custom service automatically built +* by the sdk builder. +* It provides the core functionallity for every API call, either by HTTP Calls or by +* WebSockets. +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +<% if (framework === 'react') { %> + let instance = null; +<% } %> +export class BaseLoopBackApi { + + path; + model; +<% if (framework === 'react') { -%> + models; + auth; +<% } %> + constructor( + <%- (framework === 'angular') ? buildServiceDI(isIo) : '' %> + ) { +<% if (framework === 'react') { -%> + this.models = new SDKModels(); + this.model = this.models.get(this.getModelName()); + this.auth = new LoopBackAuth(); + if (instance) { + return instance; + } + instance = this; +<% } %> +<% if (framework === 'angular') { -%> + this.model = this.models.get(this.getModelName()); +<% } %> + } + /** + * @method request + * @param {string} method Request method (GET, POST, PUT) + * @param {string} url Request url (my-host/my-url/:id) + * @param {any} routeParams Values of url parameters + * @param {any} urlParams Parameters for building url (filter and other) + * @param {any} postBody Request postBody + * @return {Observable} + * @description + * This is a core method, every HTTP Call will be done from here, every API Service will + * extend this class and use this method to get RESTful communication. + **/ + request( + method, + url, + routeParams = {}, + urlParams = {}, + postBody = {}, + pubsub = false, + customHeaders + ) { + // Transpile route variables to the actual request Values + Object.keys(routeParams).forEach((key) => { + url = url.replace(new RegExp(":" + key + "(\/|$)", "g"), routeParams[key] + "$1") + }); + if (pubsub) { +<% if ( isIo === 'enabled' ){ -%> + if (url.match(/fk/)) { + let arr = url.split('/'); arr.pop(); + url = arr.join('/'); + } + let event = (`[${method}]${url}`).replace(/\?/, ''); + let subject = new Subject(); + this.connection.on(event, (res: any) => subject.next(res)); + return subject.asObservable(); +<% } else { -%> + console.info('SDK: PubSub functionality is disabled, generate SDK using -io enabled'); +<% } -%> + } else { + // Headers to be sent +<% if ( framework === 'angular') { -%> + let headers = new Headers(); + headers.append('Content-Type', 'application/json'); +<% } %> +<% if ( framework === 'react') { -%> + +let headers = { + 'Content-Type': 'application/json' + }; +<% } %> + // Authenticate request + this.authenticate(url, headers); + // Body fix for built in remote methods using "data", "options" or "credentials + // that are the actual body, Custom remote method properties are different and need + // to be wrapped into a body object + let body; + let postBodyKeys = typeof postBody === 'object' ? Object.keys(postBody) : [] + if (postBodyKeys.length === 1) { + body = postBody[postBodyKeys.shift()]; + } else { + body = postBody; + } + let filter = ''; + // Separate filter object from url params and add to search query + if (urlParams.filter) { + if (LoopBackConfig.isHeadersFilteringSet()) { +<% if ( framework === 'angular') { -%> + headers.append('filter', JSON.stringify(urlParams.filter)); +<% } %> +<% if ( framework === 'react') { -%> + headers.filter = JSON.stringify(urlParams.filter); +<% } %> + } else { + filter = `?filter=${ encodeURI(JSON.stringify(urlParams.filter))}`; + } + delete urlParams.filter; + } + // Separate where object from url params and add to search query + /** + CODE BELOW WILL GENERATE THE FOLLOWING ISSUES: + - https://github.com/mean-expert-official/loopback-sdk-builder/issues/356 + - https://github.com/mean-expert-official/loopback-sdk-builder/issues/328 + if (urlParams.where) { + headers.append('where', JSON.stringify(urlParams.where)); + delete urlParams.where; + } + **/ + if (typeof customHeaders === 'function') { + headers = customHeaders(headers); + } +<% if (framework === 'angular') { -%> + this.searchParams.setJSON(urlParams); + let request = new Request( + new RequestOptions({ + headers : headers, + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 + ? this.searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined + }) + ); + return this.http.request(request) + .map((res) => (res.text() != "" ? res.json() : {})) + .catch((e) => this.errorHandler.handleError(e)); +<% } %> +<% if (framework === 'react') { -%> + let searchParams = new JSONSearchParams(); + let errorHandler = new ErrorHandler(); + searchParams.setJSON(urlParams); + let request = new axios.request({ + headers , + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 + ? searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined + } + ); + return Observable.fromPromise(request) + .map((res) => res.data) + .catch((e) => errorHandler.handleError(e)); +<% } %> + } + } + /** + * @method authenticate + * @author Jonathan Casarrubias + * @license MIT + * @param {string} url Server URL + * @param {Headers} headers HTTP Headers + * @return {void} + * @description + * This method will try to authenticate using either an access_token or basic http auth + */ + authenticate(url, headers) { + if (this.auth.getAccessTokenId()) { +<% if ( framework === 'angular') { -%> + headers.append( + 'Authorization', + LoopBackConfig.getAuthPrefix() + this.auth.getAccessTokenId() + ); +<% } %> +<% if ( framework === 'react') { -%> + headers.Authorization = LoopBackConfig.getAuthPrefix() + this.auth.getAccessTokenId(); +<% } %> + } + } + /** + * @method create + * @author Jonathan Casarrubias + * @license MIT + * @param {T} data Generic data type + * @return {Observable} + * @description + * Generic create method + */ + create(data, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, null, customHeaders).map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onCreate + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic pubsub oncreate many method + */ + onCreate(data) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, true) + .map((datum) => datum.map((data) => this.model.factory(data))); + } +<% } -%> + /** + * @method createMany + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic create many method + */ + createMany(data, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((datum) => datum.map((data) => this.model.factory(data))); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onCreateMany + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic create many method + */ + onCreateMany(data) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, true) + .map((datum) => datum.map((data) => this.model.factory(data))); + } +<% } -%> + /** + * @method findById + * @author Jonathan Casarrubias + * @license MIT + * @param {any} data Generic data type + * @return {Observable} + * @description + * Generic findById method + */ + findById(id, filter = {}, customHeaders) { + let _urlParams = {}; + if (filter) _urlParams.filter = filter; + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, _urlParams, undefined, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method find + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic find method + */ + find(filter = {}, customHeaders) { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, { filter }, undefined, null, customHeaders) + .map((datum) => datum.map((data) => this.model.factory(data))); + } + /** + * @method exists + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic exists method + */ + exists(id, customHeaders) { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id/exists' + ].join('/'), { id }, undefined, undefined, null, customHeaders); + } + /** + * @method findOne + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic findOne method + */ + findOne(filter = {}, customHeaders) { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'findOne' + ].join('/'), undefined, { filter }, undefined, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method updateAll + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic updateAll method + */ + updateAll(where = {}, data, customHeaders) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'update' + ].join('/'), undefined, _urlParams, { data }, null, customHeaders); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpdateAll + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpdateAll method + */ + onUpdateAll(where = {}, data) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'update' + ].join('/'), undefined, _urlParams, { data }, true); + } +<% } -%> + /** + * @method deleteById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic deleteById method + */ + deleteById(id, customHeaders) { + return this.request('DELETE', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, undefined, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onDeleteById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onDeleteById method + */ + onDeleteById(id) { + return this.request('DELETE', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, undefined, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method count + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable<{ count: number }>} + * @description + * Generic count method + */ + count(where = {}, customHeaders) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'count' + ].join('/'), undefined, _urlParams, undefined, null, customHeaders); + } + /** + * @method updateAttributes + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic updateAttributes method + */ + updateAttributes(id, data, customHeaders) { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpdateAttributes + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic onUpdateAttributes method + */ + onUpdateAttributes(id, data) { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, { data }, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method upsert + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsert method + */ + upsert(data = {}, customHeaders) { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpsert + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpsert method + */ + onUpsert(data = {}) { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method upsertPatch + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsert method using patch http method + */ + upsertPatch(data = {}, customHeaders) { + return this.request('PATCH', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpsertPatch + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpsertPatch method using patch http method + */ + onUpsertPatch(data = {}) { + return this.request('PATCH', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method upsertWithWhere + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsertWithWhere method + */ + upsertWithWhere(where = {}, data = {}, customHeaders) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'upsertWithWhere' + ].join('/'), undefined, _urlParams, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onUpsertWithWhere + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic pubsub onUpsertWithWhere method + */ + onUpsertWithWhere(where = {}, data = {}) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'upsertWithWhere' + ].join('/'), undefined, _urlParams, { data }, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method replaceOrCreate + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic replaceOrCreate method + */ + replaceOrCreate(data = {}, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'replaceOrCreate' + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onReplaceOrCreate + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic onReplaceOrCreate method + */ + onReplaceOrCreate(data = {}) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'replaceOrCreate' + ].join('/'), undefined, undefined, { data }, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method replaceById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic replaceById method + */ + replaceById(id, data = {}, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id', 'replace' + ].join('/'), { id }, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } +<% if ( isIo === 'enabled' ){ -%> + /** + * @method onReplaceById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic onReplaceById method + */ + onReplaceById(id, data = {}) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id', 'replace' + ].join('/'), { id }, undefined, { data }, true).map((data) => this.model.factory(data)); + } +<% } -%> + /** + * @method createChangeStream + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic createChangeStream method + */ + createChangeStream() { + let subject = new Subject(); + if (typeof EventSource !== 'undefined') { + let emit = (msg) => subject.next(JSON.parse(msg.data)); + var source = new EventSource([ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'change-stream' + ].join('/')); + source.addEventListener('data', emit); + source.onerror = emit; + } else { + console.warn('SDK Builder: EventSource is not supported'); + } + return subject.asObservable(); + } + /** + * @method getModelName + * @author Jonathan Casarrubias + * @license MIT + * @return {string} + * @description + * getModelName method + */ + getModelName() {}; +} +<% } %> \ No newline at end of file diff --git a/lib/templates/shared/services/core/error.ejs b/lib/templates/shared/services/core/error.ejs new file mode 100644 index 00000000..8827e440 --- /dev/null +++ b/lib/templates/shared/services/core/error.ejs @@ -0,0 +1,45 @@ +<% if (isTyped) { -%>/* tslint:disable */ +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +import { Response } from '@angular/http'; +<% } %> +import { Observable } from 'rxjs/Observable'; +//import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; +import 'rxjs/add/observable/throw'; +/** + * Default error handler + */ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class ErrorHandler { + // ErrorObservable when rxjs version < rc.5 + // ErrorObservable when rxjs version = rc.5 + // I'm leaving any for now to avoid breaking apps using both versions + public handleError(error: Response): any { + return Observable.throw(error.json().error || 'Server error'); + } +} +<% } else { -%> +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +import { Response } from '@angular/http'; +<% } %> +import { Observable } from 'rxjs/Observable'; +//import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; +import 'rxjs/add/observable/throw'; +/** + * Default error handler + */ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class ErrorHandler { + // ErrorObservable when rxjs version < rc.5 + // ErrorObservable when rxjs version = rc.5 + // I'm leaving any for now to avoid breaking apps using both versions + handleError(error) { + return Observable.throw(error.json().error || 'Server error'); + } +} +<% } %> diff --git a/lib/templates/shared/services/core/index.ejs b/lib/templates/shared/services/core/index.ejs new file mode 100644 index 00000000..b1342a4d --- /dev/null +++ b/lib/templates/shared/services/core/index.ejs @@ -0,0 +1,9 @@ +/* tslint:disable */ +export * from './auth.service'; +export * from './error.service'; +export * from './search.params'; +export * from './base.service'; +<% if ( isIo === 'enabled' ){ -%>export * from './real.time'; +<% } +-%> + diff --git a/lib/templates/shared/services/core/io.ejs b/lib/templates/shared/services/core/io.ejs new file mode 100644 index 00000000..7f775a12 --- /dev/null +++ b/lib/templates/shared/services/core/io.ejs @@ -0,0 +1,25 @@ +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Observable'; + +export class IO { + + private socket: any; + private observables: any = {}; + + constructor(socket: any) { this.socket = socket; } + + emit(event: string, data: any): void { + this.socket.emit('ME:RT:1://event', { + event : event, + data : data + }); + } + + on(event: string): Observable { + if (this.observables[event]) { return this.observables[event]; } + let subject: Subject = new Subject(); + this.socket.on(event, (res: any) => subject.next(res)); + this.observables[event] = subject.asObservable(); + return this.observables[event]; + } +} diff --git a/lib/templates/shared/services/core/logger.ejs b/lib/templates/shared/services/core/logger.ejs new file mode 100644 index 00000000..bfe37618 --- /dev/null +++ b/lib/templates/shared/services/core/logger.ejs @@ -0,0 +1,135 @@ +<% if (isTyped) { -%>/* tslint:disable */ +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +<% } %> +import { LoopBackConfig } from '../../lb.config'; +/** +* @author Jonathan Casarrubias +* @module LoggerService +* @license MIT +* @description +* Console Log wrapper that can be disabled in production mode +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class LoggerService { + + log(...args: any[]) { + if (LoopBackConfig.debuggable()) + console.log.apply(console, args); + } + + info(...args: any[]) { + if (LoopBackConfig.debuggable()) + console.info.apply(console, args); + } + + error(...args: any[]) { + if (LoopBackConfig.debuggable()) + console.error.apply(console, args); + } + + count(arg: string) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + group(arg: string) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + groupEnd() { + if (LoopBackConfig.debuggable()) + console.groupEnd(); + } + + profile(arg: string) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + profileEnd() { + if (LoopBackConfig.debuggable()) + console.profileEnd(); + } + + time(arg: string) { + if (LoopBackConfig.debuggable()) + console.time(arg); + } + + timeEnd(arg: string) { + if (LoopBackConfig.debuggable()) + console.timeEnd(arg); + } +} +<% } else { -%> +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +<% } %> +import { LoopBackConfig } from '../../lb.config'; +/** +* @author Jonathan Casarrubias +* @module LoggerService +* @license MIT +* @description +* Console Log wrapper that can be disabled in production mode +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class LoggerService { + + log(...args) { + if (LoopBackConfig.debuggable()) + console.log.apply(console, args); + } + + info(...args) { + if (LoopBackConfig.debuggable()) + console.info.apply(console, args); + } + + error(...args) { + if (LoopBackConfig.debuggable()) + console.error.apply(console, args); + } + + count(arg) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + group(arg) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + groupEnd() { + if (LoopBackConfig.debuggable()) + console.groupEnd(); + } + + profile(arg) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + profileEnd() { + if (LoopBackConfig.debuggable()) + console.profileEnd(); + } + + time(arg) { + if (LoopBackConfig.debuggable()) + console.time(arg); + } + + timeEnd(arg) { + if (LoopBackConfig.debuggable()) + console.timeEnd(arg); + } +} +<% } %> \ No newline at end of file diff --git a/lib/templates/shared/services/core/realtime.ts b/lib/templates/shared/services/core/realtime.ts new file mode 100644 index 00000000..ec3e1c74 --- /dev/null +++ b/lib/templates/shared/services/core/realtime.ts @@ -0,0 +1,114 @@ +import { Injectable, Inject } from '@angular/core'; +import { IO } from './io.service'; +import { LoopBackAuth } from './auth.service'; +import { FireLoop } from '../../models/FireLoop'; +import { SocketConnection } from '../../sockets/socket.connections'; +import { SDKModels } from '../custom/SDKModels'; +import { Observable } from 'rxjs/Rx'; +import { Subject } from 'rxjs/Subject'; +import { Subscription } from 'rxjs/Subscription'; +/** +* @author Jonathan Casarrubias +* @module RealTime +* @license MIT +* @description +* This module is a real-time interface for using socket connections, its main purpose +* is to make sure that when there is a valid connection, it will create instances +* of the different real-time functionalities like FireLoop, PubSub and IO. +**/ +@Injectable() +export class RealTime { + public IO: IO; + public FireLoop: FireLoop; + private connecting: boolean = false; + private onReadySubject: Subject = new Subject(); + private sharedOnReady: Observable = this.onReadySubject.asObservable().share(); + /** + * @method constructor + * @param {SocketConnection} connection WebSocket connection service + * @param {SDKModels} models Model provider service + * @param {LoopBackAuth} auth LoopBack authentication service + * @description + * It will intialize the shared on ready communication channel. + **/ + constructor( + @Inject(SocketConnection) public connection: SocketConnection, + @Inject(SDKModels) protected models: SDKModels, + @Inject(LoopBackAuth) protected auth: LoopBackAuth + ) { + this.sharedOnReady.subscribe(); + } + /** + * @method onDisconnect + * @return {Observable} + * @description + * Will trigger when Real-Time Service is disconnected from server. + **/ + onDisconnect(): Observable { + return this.connection.sharedObservables.sharedOnDisconnect; + } + /** + * @method onAuthenticated + * @return {Observable} + * @description + * Will trigger when Real-Time Service is authenticated with the server. + **/ + onAuthenticated(): Observable { + return this.connection.sharedObservables.sharedOnAuthenticated; + } + /** + * @method onUnAuthorized + * @return {Observable} + * @description + * Will trigger when Real-Time Service is not authorized to connect with the server. + **/ + onUnAuthorized(): Observable { + return this.connection.sharedObservables.sharedOnUnAuthorized; + } + /** + * @method onReady + * @return {Observable} + * @description + * Will trigger when Real-Time Service is Ready for broadcasting. + * and will register connection flow events to notify subscribers. + **/ + public onReady(): Observable { + // If there is a valid connection, then we just send back to the EventLoop + // Or next will be executed before the actual subscription. + if (this.connection.isConnected()) { + let to = setTimeout(() => { + this.onReadySubject.next('shared-connection'); + clearTimeout(to); + }); + // Else if there is a current attempt of connection we wait for the prior + // process that started the connection flow. + } else if (this.connecting) { + let ti = setInterval(() => { + if (this.connection.isConnected()) { + this.onReadySubject.next('shared-connection'); + clearInterval(ti); + } + }, 500); + // If there is not valid connection or attempt, then we start the connection flow + // and make sure we notify all the onReady subscribers when done. + // Also it will listen for desconnections so we unsubscribe and avoid both: + // Memory leaks and duplicated triggered events. + } else { + this.connecting = true; + this.connection.connect(this.auth.getToken()); + this.IO = new IO(this.connection); + this.FireLoop = new FireLoop(this.connection, this.models); + // Fire event for those subscribed + let s1: Subscription = this.connection.sharedObservables.sharedOnConnect.subscribe(() => { + console.log('Real-Time connection has been established'); + this.connecting = false; + this.onReadySubject.next('connected'); + let s2: Subscription = this.connection.sharedObservables.sharedOnDisconnect.subscribe(() => { + s1.unsubscribe(); + s2.unsubscribe(); + }); + }); + } + return this.sharedOnReady; + } +} diff --git a/lib/templates/shared/services/core/search.ejs b/lib/templates/shared/services/core/search.ejs new file mode 100644 index 00000000..856cacf2 --- /dev/null +++ b/lib/templates/shared/services/core/search.ejs @@ -0,0 +1,94 @@ +<% if (isTyped) { -%>/* tslint:disable */ +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +import { URLSearchParams } from '@angular/http'; +<% } %> +/** +* @author Jonathan Casarrubias +* @module JSONSearchParams +* @license MIT +* @description +* JSON Parser and Wrapper for the Angular2 URLSearchParams +* This module correctly encodes a json object into a query string and then creates +* an instance of the URLSearchParams component for later use in HTTP Calls +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class JSONSearchParams { + + private _usp: URLSearchParams; + + public setJSON(obj: any) { + this._usp = new URLSearchParams(this._JSON2URL(obj, false)); + } + + public getURLSearchParams(): URLSearchParams { + return this._usp; + } + + private _JSON2URL(obj: any, parent: any) { + var parts: any = []; + for (var key in obj) + parts.push(this._parseParam(key, obj[key], parent)); + return parts.join('&'); + } + + private _parseParam(key: string, value: any, parent: string) { + let processedKey = parent ? parent + '[' + key + ']' : key; + if (value && ((typeof value) === 'object' || Array.isArray(value))) { + return this._JSON2URL(value, processedKey); + } + return processedKey + '=' + value; + } +} +<% } else { -%> +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +import { URLSearchParams } from '@angular/http'; +<% } %> +/** +* @author Jonathan Casarrubias +* @module JSONSearchParams +* @license MIT +* @description +* JSON Parser and Wrapper for the Angular2 URLSearchParams +* This module correctly encodes a json object into a query string and then creates +* an instance of the URLSearchParams component for later use in HTTP Calls +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class JSONSearchParams { + + _usp; + + setJSON(obj) { +<% if (framework === 'angular') { -%> + this._usp = new URLSearchParams(this._JSON2URL(obj, false)); +<% } %> +<% if (framework === 'react') { -%> + this._usp = this._JSON2URL(obj, false); +<% } %> + } + + getURLSearchParams() { + return this._usp; + } + + _JSON2URL(obj, parent) { + var parts = []; + for (var key in obj) + parts.push(this._parseParam(key, obj[key], parent)); + return parts.join('&'); + } + + _parseParam(key, value, parent) { + let processedKey = parent ? parent + '[' + key + ']' : key; + if (value && ((typeof value) === 'object' || Array.isArray(value))) { + return this._JSON2URL(value, processedKey); + } + return processedKey + '=' + value; + } +} +<% } %> diff --git a/lib/templates/shared/services/custom/index.ejs b/lib/templates/shared/services/custom/index.ejs new file mode 100644 index 00000000..cd236cbd --- /dev/null +++ b/lib/templates/shared/services/custom/index.ejs @@ -0,0 +1,10 @@ +/* tslint:disable */ +<% for (var modelName in models) { + var meta = models[modelName]; + // capitalize the model name + modelName = modelName[0].toUpperCase() + modelName.slice(1); +-%> +export * from './<%- modelName %>'; +<% } // for modelName in models -%> +export * from './SDKModels'; +export * from './logger.service'; diff --git a/lib/templates/shared/services/custom/models.ejs b/lib/templates/shared/services/custom/models.ejs new file mode 100644 index 00000000..439af5b7 --- /dev/null +++ b/lib/templates/shared/services/custom/models.ejs @@ -0,0 +1,51 @@ +<% if (isTyped) { -%>/* tslint:disable */<% } -%> +<% if (framework === 'angular') { -%>import { Injectable } from '@angular/core';<% } -%> +<% for (var modelName in models) { + var meta = models[modelName]; + // capitalize the model name + modelName = modelName[0].toUpperCase() + modelName.slice(1); +-%> +import { <%- modelName %> } from '../../models/<%- modelName %>'; +<% } // for modelName in models -%> +<% if (isTyped) { -%> +export interface Models { [name: string]: any } +<% } -%> +<% if (framework === 'angular') { -%> +@Injectable() +<% } -%> +export class SDKModels { +<% if (isTyped) { -%> + private models: Models = { + <% for ( modelName in models ) { %><%= modelName %>: <%= modelName %>, + <% } %>}; + + public get(modelName: string): any { + return this.models[modelName]; + } + + public getAll(): Models { + return this.models; + } + + public getModelNames(): string[] { + return Object.keys(this.models); + } +<% } else { -%> + models = { + <% for ( modelName in models ) { %><%= modelName %>: <%= modelName %>, + <% } %> + }; + + get(modelName) { + return this.models[modelName]; + } + + getAll() { + return this.models; + } + + getModelNames() { + return Object.keys(this.models); + } +<% } -%> +} diff --git a/lib/templates/shared/services/custom/service.ejs b/lib/templates/shared/services/custom/service.ejs new file mode 100644 index 00000000..d5f44f76 --- /dev/null +++ b/lib/templates/shared/services/custom/service.ejs @@ -0,0 +1,362 @@ +/* tslint:disable */ +<%- buildServiceImports(model, loadAccessToken, isIo, models) %> + + +/** + * Api services for the `<%-: modelName %>` model. +<% if ( model.description ){ -%> + * + * **Details** + * + * <%-: model.description | replace:/\n/gi, '\n * ' %> +<% } -%> + */ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class <%-: modelName %>Api extends BaseLoopBackApi { + + constructor( + <% (framework === 'angular') ? buildServiceDI(isIo): '' %> + ) { + <% if (framework === 'angular') { -%> + super(http, <% if (isIo === 'enabled') { %> connection, <% } %> models, auth, searchParams, errorHandler); + <% } else { %> + super(); + <% } %> + } +<% model.methods.forEach(function(action) { + + var methodName = action.name.split('.').join('$').replace('prototype$', '').replace(/::/g, '__'); + var httpVerb = (action.getEndpoints ? action.getEndpoints()[0].verb : action.getHttpMethod()).toUpperCase(); + var fullPath = action.getEndpoints ? action.getEndpoints()[0].fullPath : action.getFullPath(); + + // all of these methods are extended from base service + if (methodName.match(/(^create$|^createMany$|^find$|^replaceOrCreate$|^replaceById$|^upsert$|^upsertWithWhere$|^exists$|^findOne$|^findById$|^deleteById$|^updateAttributes$|^updateAll$|^count$|^createChangeStream$)/)) { return; } + + if (!model.sharedClass.ctor.settings.sdk.blacklist[methodName]) { + ngdocForMethod(modelName, methodName, action, httpVerb, fullPath); + + // SET URL PARAMS + var urlParams = action.accepts; + // SET POST BODY + var postData; + if (httpVerb == 'POST' || httpVerb == 'PUT' || httpVerb == 'PATCH') { + postData = action.accepts; + } + // SET ROUTE PARAMS + var routeParams = action.accepts +-%> + <% if(isTyped) { %>public<% } %> <%- normalizeMethodName(methodName) %>(<%- buildMethodParams(model, methodName, action.accepts, false, models) %>)<% if(isTyped) { %>: Observable<<%- buildObservableType(model, action) %>> <% } %> { + <% if(isTyped) { -%> + let _method: string = <%-: httpVerb | q %>; + let _url: string = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + <%-: fullPath | q %>; + let _routeParams: any = {<%- buildRouteParams(routeParams) %>}; + let _postBody: any = {<%- buildPostBody(postData) %>}; + let _urlParams: any = {}; + <% } else { %> + let _method = <%-: httpVerb | q %>; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + <%-: fullPath | q %>; + let _routeParams = {<%- buildRouteParams(routeParams) %>}; + let _postBody = {<%- buildPostBody(postData) %>}; + let _urlParams = {}; + <% } %> + <%- buildUrlParams(model, methodName, urlParams) %><% + if (model.isUser && methodName === 'logout') { %> + this.auth.clear(); <% + } -%> + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders)<% +if (model.isUser && methodName === 'login') { %> + .map( + (response<% if(isTyped) { %>: any<% } %>) => { + response.ttl = parseInt(response.ttl); + response.rememberMe = rememberMe; + this.auth.setToken(response); + return response; + } + ); + return result; + <% +} else if (methodName.match(/(^create$|upsert|^findBy|^findOne$)/g)) { %>; + return result.map((instance: <%- modelName %>) => new <%-: modelName %>(instance));<% +} else if (methodName.match(/(^createMany$|^find)/g)) { %>; + return result.map((instances: Array<<%- modelName %>>) => + instances.map((instance: <%- modelName %>) => new <%-: modelName %>(instance)) + );<% +} else { %>; + return result;<% +} %> + } +<% if ( isIo === 'enabled' && + (model.sharedClass.ctor.settings.mixins && model.sharedClass.ctor.settings.mixins.PubSub) && + !methodName.match(/log(in|out)/g) && + methodName !== 'resetPassword' && + httpVerb !== 'GET' && + httpVerb !== 'HEAD'){ +-%> + + public on<%- normalizeMethodName(methodName, true) %>(<%- buildMethodParams(model, methodName, action.accepts, true, models) %>): Observable<<%- buildObservableType(model, action) %>> { + let _method: string = <%-: httpVerb | q %>; + let _url: string = "/" + LoopBackConfig.getApiVersion() + + <%-: fullPath | q %>; + let _routeParams: any = {<%- buildRouteParams(routeParams.filter(function(param) { return param.arg !== 'fk'; })) %>}; + let _postBody: any = {}; + let _urlParams: any = {}; + return this.request(_method, _url, _routeParams, _urlParams, _postBody, true); + } +<% }} -%> +<% }); // model.methods.foreach -%> + +<% if (isTyped) { -%> +<% if (model.isUser) { -%> + /** + * @ngdoc method + * @name <%- moduleName %>.<%- modelName %>#getCurrent + * @methodOf <%- moduleName %>.<%- modelName %> + * + * @description + * + * Get data of the currently logged user. Fail with HTTP result 401 + * when there is no user logged in. + * + * @returns object An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + */ + public getCurrent(filter: LoopBackFilter = {}): Observable { + let _method: string = "GET"; + let _url: string = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + <%-: model.getPath() | q %> + "/:id"; + let id: any = this.auth.getCurrentUserId(); + if (id == null) + id = '__anonymous__'; + let _routeParams: any = { id: id }; + let _urlParams: any = {}; + let _postBody: any = {}; + if (filter) _urlParams.filter = filter; + return this.request(_method, _url, _routeParams, _urlParams, _postBody); + } + /** + * Get data of the currently logged user that was returned by the last + * call to {@link <%- moduleName %>.<%- modelName %>#login} or + * {@link <%- moduleName %>.<%- modelName %>#getCurrent}. Return null when there + * is no user logged in or the data of the current user were not fetched + * yet. + * + * @returns object An Account instance. + */ + public getCachedCurrent() { + return this.auth.getCurrentUserData(); + } + /** + * Get data of the currently logged access tokern that was returned by the last + * call to {@link <%- moduleName %>.<%- modelName %>#login} + * + * @returns object An AccessToken instance. + */ + public getCurrentToken(): AccessToken { + return this.auth.getToken(); + } + /** + * @name <%- moduleName %>.<%- modelName %>#isAuthenticated + * + * @returns {boolean} True if the current user is authenticated (logged in). + */ + public isAuthenticated() { + return !(this.getCurrentId() === '' || this.getCurrentId() == null || this.getCurrentId() == 'null'); + } + + /** + * @name <%- moduleName %>.<%- modelName %>#getCurrentId + * + * @returns object Id of the currently logged-in user or null. + */ + public getCurrentId() { + return this.auth.getCurrentUserId(); + } +<% } -%> + + /** + * The name of the model represented by this $resource, + * i.e. `<%- modelName %>`. + */ + public getModelName() { + return <%-: modelName | q %>; + } +} +<% } else { %> +<% if (model.isUser) { -%> + /** + * @ngdoc method + * @name <%- moduleName %>.<%- modelName %>#getCurrent + * @methodOf <%- moduleName %>.<%- modelName %> + * + * @description + * + * Get data of the currently logged user. Fail with HTTP result 401 + * when there is no user logged in. + * + * @returns object An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + */ + getCurrent(filter = {}) { + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + <%-: model.getPath() | q %> + "/:id"; + let id = this.auth.getCurrentUserId(); + if (id == null) + id = '__anonymous__'; + let _routeParams = { id: id }; + let _urlParams = {}; + let _postBody = {}; + if (filter) _urlParams.filter = filter; + return this.request(_method, _url, _routeParams, _urlParams, _postBody); + } + /** + * Get data of the currently logged user that was returned by the last + * call to {@link <%- moduleName %>.<%- modelName %>#login} or + * {@link <%- moduleName %>.<%- modelName %>#getCurrent}. Return null when there + * is no user logged in or the data of the current user were not fetched + * yet. + * + * @returns object An Account instance. + */ + getCachedCurrent() { + return this.auth.getCurrentUserData(); + } + /** + * Get data of the currently logged access tokern that was returned by the last + * call to {@link <%- moduleName %>.<%- modelName %>#login} + * + * @returns object An AccessToken instance. + */ + getCurrentToken() { + return this.auth.getToken(); + } + /** + * @name <%- moduleName %>.<%- modelName %>#isAuthenticated + * + * @returns {boolean} True if the current user is authenticated (logged in). + */ + isAuthenticated() { + return !(this.getCurrentId() === '' || this.getCurrentId() == null || this.getCurrentId() == 'null'); + } + + /** + * @name <%- moduleName %>.<%- modelName %>#getCurrentId + * + * @returns object Id of the currently logged-in user or null. + */ + getCurrentId() { + return this.auth.getCurrentUserId(); + } +<% } -%> + + /** + * The name of the model represented by this $resource, + * i.e. `<%- modelName %>`. + */ + getModelName() { + return <%-: modelName | q %>; + } +} +<% } %> +<% +function getJsDocType(arg) { + return arg.type; +} + +function ngdocForMethod(modelName, methodName, action, httpVerb, fullPath) { + // always add an empty line before the ngdoc comment: +-%> + + /** +<% if (action.deprecated) { -%> + * @deprecated <%- action.deprecated %> +<% } -%> +<% if (!action.description) { +action.description = '\n' + + '(The remote method definition does not provide any description.)\n' + + ''; +} -%> + * <%-: action.description | replace:/\n/g, '\n * ' %> +<% +var params = action.accepts.filter(param => { + return !paramIsContext(param); +}); + +var postData; +if (httpVerb == 'POST' || httpVerb == 'PUT' || httpVerb == 'PATCH') { + params = params.filter(function(arg) { + return arg.http && (arg.http.source == 'query' || arg.http.source == 'path'); + }); + postData = action.accepts.filter(function(arg) { + return params.indexOf(arg) == -1 && !paramIsContext(arg) && !paramIsFunction(arg); + }); +} +-%> +<% if (params.length != 0) { + params.forEach(function(arg) { -%> + * + * @param {<%- getJsDocType(arg) %>} <%- arg.arg %> <%- +(arg.description ? (Array.isArray(arg.description) ? arg.description.join('\n') : arg.description) : '').replace(/\n/g, '\n * ') %> +<% if (model.isUser && methodName === 'login' && arg.arg === 'include') { -%> + * Default value: `user`. +<% } -%> +<% }); } -%> +<% if (model.isUser && methodName === 'login') { -%> + * + * - `rememberMe` - `boolean` - Whether the authentication credentials + * should be remembered in localStorage across app/browser restarts. + * Default: `true`. +<% } -%> +<% if (postData) { -%> + * + * @param {object} data Request data. +<% if (postData.length == 0) { -%> + * + * This method does not accept any data. Supply an empty object. +<% } else if (postData.length == 1 && postData[0].http && + postData[0].http.source == 'body' && + !postData[0].description) { -%> + * + * This method expects a subset of model properties as request parameters. +<% } else { +postData.forEach(function(arg) { -%> + * + * - `<%- arg.arg %>` – `{<%- getJsDocType(arg) %>}` - <%- +(arg.description ? (Array.isArray(arg.description) ? arg.description.join('\n') : arg.description) : '').replace(/\n/g, '\n * ') %> +<% }); + } +} -%> + * +<% var returnType = action.isReturningArray() ? 'object[]': 'object'; -%> + * @returns {<%- returnType %>} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * +<% if (!action.returns || action.returns.length == 0) { -%> + * This method returns no data. +<% } else if (action.returns[0].root) { -%> +<% if (action.returns[0].description) { -%> + * <%- action.returns[0].description +.replace(/\n/g, '\n * ').trimRight() %> +<% } else { -%> + * + * (The remote method definition does not provide any description. + * This usually means the response is a `<%- modelName %>` object.) + * +<% } -%> +<% } else { -%> + * Data properties: +<% action.returns.forEach(function(arg) { -%> + * + * - `<%- arg.arg %>` – `{<%- getJsDocType(arg) %>}` - <%- +(arg.description ? (Array.isArray(arg.description) ? arg.description.join('\n') : arg.description) : '').replace(/\n/g, '\n * ') %> +<% }); + } +-%> + */ +<% } // end of ngdocForMethod -%> diff --git a/lib/templates/shared/services/index.ejs b/lib/templates/shared/services/index.ejs new file mode 100644 index 00000000..bd1dcfa6 --- /dev/null +++ b/lib/templates/shared/services/index.ejs @@ -0,0 +1,3 @@ +/* tslint:disable */ +export * from './core/index'; +export * from './custom/index'; diff --git a/lib/templates/shared/storage/cookie.browser.ejs b/lib/templates/shared/storage/cookie.browser.ejs new file mode 100644 index 00000000..d4c24239 --- /dev/null +++ b/lib/templates/shared/storage/cookie.browser.ejs @@ -0,0 +1,152 @@ +<% if (framework === 'angular') { %> +import { Injectable } from '@angular/core'; +<% if (isTyped) { %> +export interface CookieInterface { [key: string]: any } +<% } %> +<% } %> +/** +* @author Jonathan Casarrubias +* @module CookieBrowser +* @license MIT +* @description +* This module handle cookies, it will be provided using DI Swapping according the +* SDK Socket Driver Available currently supporting Angular 2 for web and NativeScript 2. +**/ +<% if (framework === 'angular') { %> +@Injectable() +<% } %> +export class CookieBrowser { + <% if (isTyped) { -%> + /** + * @type {CookieInterface} + **/ + private cookies: CookieInterface = {}; + /** + * @method get + * @param {string} key Cookie key name + * @return {any} + * @description + * The getter will return any type of data persisted in cookies. + **/ + get(key: string): any { + if (!this.cookies[key]) { + let cookie = window.document + .cookie.split('; ') + .filter((item: any) => item.split('=')[0] === key).pop(); + if (!cookie) { + return null; + } + + this.cookies[key] = this.parse(cookie.split('=').slice(1).join('=')); + } + + return this.cookies[key]; + } + /** + * @method set + * @param {string} key Cookie key name + * @param {any} value Any value + * @param {Date=} expires The date of expiration (Optional) + * @return {void} + * @description + * The setter will return any type of data persisted in cookies. + **/ + set(key: string, value: any, expires?: Date): void { + this.cookies[key] = value; + let cookie = `${key}=${value}; path=/${expires ? `; expires=${ expires.toUTCString() }` : ''}`; + window.document.cookie = cookie; + } + /** + * @method remove + * @param {string} key Cookie key name + * @return {void} + * @description + * This method will remove a cookie from the client. + **/ + remove(key: string) { + document.cookie = key + '=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + delete this.cookies[key]; + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + private parse(value: any) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + <% } else { %> + /** + * @type {CookieInterface} + **/ + cookies = {}; + /** + * @method get + * @param {string} key Cookie key name + * @return {any} + * @description + * The getter will return any type of data persisted in cookies. + **/ + get(key) { + if (!this.cookies[key]) { + let cookie = window.document + .cookie.split('; ') + .filter((item) => item.split('=')[0] === key).pop(); + if (!cookie) { + return null; + } + + this.cookies[key] = this.parse(cookie.split('=').slice(1).join('=')); + } + + return this.cookies[key]; + } + /** + * @method set + * @param {string} key Cookie key name + * @param {any} value Any value + * @param {Date=} expires The date of expiration (Optional) + * @return {void} + * @description + * The setter will return any type of data persisted in cookies. + **/ + set(key, value, expires) { + this.cookies[key] = value; + let cookie = `${key}=${value}; path=/${expires ? `; expires=${ expires.toUTCString() }` : ''}`; + window.document.cookie = cookie; + } + /** + * @method remove + * @param {string} key Cookie key name + * @return {void} + * @description + * This method will remove a cookie from the client. + **/ + remove(key) { + document.cookie = key + '=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + delete this.cookies[key]; + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + parse(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + <% } %> +} diff --git a/lib/templates/shared/storage/cookie.node.ejs b/lib/templates/shared/storage/cookie.node.ejs new file mode 100644 index 00000000..7c6ddd76 --- /dev/null +++ b/lib/templates/shared/storage/cookie.node.ejs @@ -0,0 +1,88 @@ +<% if (framework === 'angular') { %> +import { Injectable } from '@angular/core'; +<% if (isTyped) { %> +declare var Zone: any; +<% } %> +<% } %> +/** +* @author Jonathan Casarrubias +* @module CookieNode +* @license MIT +* @description +* This module handle cookies, it will be provided using DI Swapping according the +* SDK Socket Driver Available currently supporting Angular 2 for web and NativeScript 2. +**/ +<% if (framework === 'angular') { %> +@Injectable() +<% } %> +export class CookieNode { + <% if (isTyped) { -%> + /** + * @method get + * @param {string} key Cookie key name + * @return {any} + * @description + * The getter will return any type of data persisted in cookies. + **/ + get(key: string) { + let cookies: { [key: string]: number } = Zone.current.get('req').cookies; + return cookies[key]; + } + /** + * @method set + * @param {string} key Cookie key name + * @param {any} value Any value + * @param {Date=} expires The date of expiration (Optional) + * @return {void} + * @description + * The setter will return any type of data persisted in cookies. + **/ + set(key: string, value: any): any { + Zone.current.get('res').cookies(key, value).send('Cookie is set'); + } + /** + * @method remove + * @param {string} key Cookie key name + * @return {void} + * @description + * This method will remove a cookie from the client. + **/ + remove(key: string, value: any): any { + Zone.current.get('res').cookies(key, '; expires=Thu, 01 Jan 1970 00:00:01 GMT;').send('Cookie is removed'); + } + <% } else { %> + /** + * @method get + * @param {string} key Cookie key name + * @return {any} + * @description + * The getter will return any type of data persisted in cookies. + **/ + get(key) { + let cookies = Zone.current.get('req').cookies; + return cookies[key]; + } + /** + * @method set + * @param {string} key Cookie key name + * @param {any} value Any value + * @param {Date=} expires The date of expiration (Optional) + * @return {void} + * @description + * The setter will return any type of data persisted in cookies. + **/ + set(key, value) { + Zone.current.get('res').cookies(key, value).send('Cookie is set'); + } + /** + * @method remove + * @param {string} key Cookie key name + * @return {void} + * @description + * This method will remove a cookie from the client. + **/ + remove(key, value) { + Zone.current.get('res').cookies(key, '; expires=Thu, 01 Jan 1970 00:00:01 GMT;').send('Cookie is removed'); + } + <% } %> +} diff --git a/lib/templates/shared/storage/storage.browser.ejs b/lib/templates/shared/storage/storage.browser.ejs new file mode 100644 index 00000000..8c79f561 --- /dev/null +++ b/lib/templates/shared/storage/storage.browser.ejs @@ -0,0 +1,128 @@ +<% if (isTyped) { -%>/* tslint:disable */<% } %> +<% if (framework === 'angular') { -%> +import { Injectable } from '@angular/core'; +<% } %> +/** +* @author Jonathan Casarrubias +* @module StorageBrowser +* @license MIT +* @description +* This module handle localStorage, it will be provided using DI Swapping according the +* SDK Socket Driver Available currently supporting Angular 2 for web and NativeScript 2. +**/ +<% if (framework === 'angular') { -%> +@Injectable() +<% } %> +export class StorageBrowser { + <% if (isTyped) { %> + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in localStorage. + **/ + get(key: string): any { + let data: string = localStorage.getItem(key); + return this.parse(data); + } + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key: string, value: any): void { + localStorage.setItem( + key, + typeof value === 'object' ? JSON.stringify(value) : value + ); + } + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key: string): void { + if (localStorage[key]) { + localStorage.removeItem(key); + } else { + console.log('Trying to remove unexisting key: ', key); + } + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + private parse(value: any) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + <% } else { %> + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in localStorage. + **/ + get(key){ + let data = localStorage.getItem(key); + return this.parse(data); + } + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key, value) { + localStorage.setItem( + key, + typeof value === 'object' ? JSON.stringify(value) : value + ); + } + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key) { + if (localStorage[key]) { + localStorage.removeItem(key); + } else { + console.log('Trying to remove unexisting key: ', key); + } + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + parse(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + <% } %> +} diff --git a/lib/templates/shared/storage/storage.native.ejs b/lib/templates/shared/storage/storage.native.ejs new file mode 100644 index 00000000..14acf3d5 --- /dev/null +++ b/lib/templates/shared/storage/storage.native.ejs @@ -0,0 +1,68 @@ +/* tslint:disable */ +import * as AppSettings from 'application-settings'; +import { Injectable } from '@angular/core'; +/** +* @author Jonathan Casarrubias +* @module StorageNative +* @license MIT +* @description +* This module handle localStorage, it will be provided using DI Swapping according the +* SDK Socket Driver Available currently supporting Angular 2 for web and NativeScript 2. +**/ +@Injectable() +export class StorageNative { + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in localStorage. + **/ + get(key: string): any { + let data: string = AppSettings.getString(key); + return this.parse(data); + } + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key: string, value: any): void { + AppSettings.setString( + key, + String(typeof value === 'object' ? JSON.stringify(value) : value) + ); + } + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key: string): any { + if (AppSettings.hasKey(key)) { + AppSettings.remove(key); + } else { + console.log('Trying to remove unexisting key: ', key); + } + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + private parse(value: any) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } +} diff --git a/lib/templates/shared/storage/storage.swaps.ejs b/lib/templates/shared/storage/storage.swaps.ejs new file mode 100644 index 00000000..bfe4acbc --- /dev/null +++ b/lib/templates/shared/storage/storage.swaps.ejs @@ -0,0 +1,87 @@ +/** + * @module Storage + * @author Jonathan Casarrubias + * @license MIT + * @description + * The InternalStorage class is used for dependency injection swapping. + * It will be provided using factory method from different sources. + **/ +<% if (isTyped) { -%> +export class BaseStorage { + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in storage. + **/ + get(key: string): any {} + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key: string, value: any): void {} + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key: string): void {} +} +<% } else { -%> +export class BaseStorage { + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in storage. + **/ + get(key) {} + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key, value) {} + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key) {} +} +<% } %> +/** + * @module InternalStorage + * @author Jonathan Casarrubias + * @license MIT + * @description + * The InternalStorage class is used for dependency injection swapping. + * It will be provided using factory method from different sources. + * This is mainly required because Angular Universal integration. + * It does inject a CookieStorage instead of LocalStorage. + **/ +export class InternalStorage extends BaseStorage {} +/** + * @module SDKStorage + * @author Jonathan Casarrubias + * @license MIT + * @description + * The SDKStorage class is used for dependency injection swapping. + * It will be provided using factory method according the right environment. + * This is created for public usage, to allow persisting custom data + * Into the local storage API. + **/ +export class SDKStorage extends BaseStorage {} diff --git a/lib/utils.js b/lib/utils.js index 55f270e5..c7a33faa 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -36,8 +36,12 @@ exports.describeModels = function describeModels(app) { // Tell SDK Builder to generate model by default, unless user c.sharedClass.ctor.settings = Object.assign( {}, - c.sharedClass.ctor.settings, - { sdk: { enabled: true }} + c.sharedClass.ctor.settings + ); + c.sharedClass.ctor.settings.sdk = Object.assign( + {}, + c.sharedClass.ctor.settings.sdk, + {enabled: true} ); // Tell SDK to blacklist specific methods c.sharedClass.ctor.settings.sdk.blacklist = Object.assign( diff --git a/package-lock.json b/package-lock.json index 544e7df7..a21077a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,132 +4,16 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@mean-expert/loopback-component-realtime": { - "version": "1.0.0-rc.8.7", - "resolved": "https://registry.npmjs.org/@mean-expert/loopback-component-realtime/-/loopback-component-realtime-1.0.0-rc.8.7.tgz", - "integrity": "sha1-gf19xUCZeHgFBi3iS8WAt5qvCnY=", - "requires": { - "async": "2.4.1", - "chalk": "1.1.3", - "loopback-context": "1.0.0", - "socket.io": "1.7.4", - "socket.io-client": "1.7.4", - "socketio-auth": "0.0.5" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "accepts": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", - "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", - "requires": { - "mime-types": "2.1.15", - "negotiator": "0.6.1" - } - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" - }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "requires": { - "color-convert": "1.9.0" - } - }, - "arraybuffer.slice": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", - "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" - }, - "async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.4.1.tgz", - "integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=", - "requires": { - "lodash": "4.17.4" - } - }, - "async-listener": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.5.tgz", - "integrity": "sha1-LImdSaXoot6hC5RzkVtBSSBqHWg=", - "requires": { - "semver": "5.3.0", - "shimmer": "1.1.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" - } - } - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" - }, - "base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" - }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "requires": { - "callsite": "1.0.0" - } - }, - "blob": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" - }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", @@ -139,157 +23,40 @@ "concat-map": "0.0.1" } }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" - }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "3.2.0", + "ansi-styles": "2.2.1", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" - } - }, - "color-convert": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", - "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", - "requires": { - "color-name": "1.1.3" + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" - }, - "component-emitter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", - "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "continuation-local-storage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.0.tgz", - "integrity": "sha1-4Z/Da1lwkKXU5KOy6j68XilpSiQ=", - "requires": { - "async-listener": "0.6.5", - "emitter-listener": "1.0.1" - } - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "requires": { - "ms": "0.7.2" - } - }, "ejs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ejs/-/ejs-1.0.0.tgz", "integrity": "sha1-ycYKSKRu5FL7MqccMXuV5aofyz0=" }, - "emitter-listener": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.0.1.tgz", - "integrity": "sha1-skmepuWCMKUsJo1d8mHuzZ8Q/pc=", - "requires": { - "shimmer": "1.0.0" - }, - "dependencies": { - "shimmer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.0.0.tgz", - "integrity": "sha1-ScLXHGeDYLgCvhiyeDgtHLuAXDk=" - } - } - }, - "engine.io": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.4.tgz", - "integrity": "sha1-d7zhK4Dl1gQpM3/sOw2vaR68kAM=", - "requires": { - "accepts": "1.3.3", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "ws": "1.1.4" - } - }, - "engine.io-client": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.4.tgz", - "integrity": "sha1-n+hd7iWFPKa6viW9KtaHEIY+kcI=", - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parsejson": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "1.1.2", - "xmlhttprequest-ssl": "1.5.3", - "yeast": "0.1.2" - }, - "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - }, - "ws": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", - "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=", - "requires": { - "options": "0.0.6", - "ultron": "1.0.2" - } - } - } - }, - "engine.io-parser": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", - "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "0.0.6", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", - "has-binary": "0.1.7", - "wtf-8": "1.0.0" - } - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -329,29 +96,6 @@ "ansi-regex": "2.1.1" } }, - "has-binary": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", - "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", - "requires": { - "isarray": "0.0.1" - } - }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -366,42 +110,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "loopback-context": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/loopback-context/-/loopback-context-1.0.0.tgz", - "integrity": "sha1-MMmyMVzqsD7JAac5QudhTNk+lUg=", - "requires": { - "continuation-local-storage": "3.2.0" - } - }, - "mime-db": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" - }, - "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", - "requires": { - "mime-db": "1.27.0" - } - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -423,26 +131,6 @@ "minimist": "0.0.8" } }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, - "object-assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" - }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -460,35 +148,6 @@ "wordwrap": "0.0.3" } }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" - }, - "parsejson": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", - "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", - "requires": { - "better-assert": "1.0.2" - } - }, - "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "requires": { - "better-assert": "1.0.2" - } - }, - "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "requires": { - "better-assert": "1.0.2" - } - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -507,101 +166,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, - "shimmer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.1.0.tgz", - "integrity": "sha1-l9c3cTf/u6tCVSLkKf4KqJpIizU=" - }, - "socket.io": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", - "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", - "requires": { - "debug": "2.3.3", - "engine.io": "1.8.4", - "has-binary": "0.1.7", - "object-assign": "4.1.0", - "socket.io-adapter": "0.5.0", - "socket.io-client": "1.7.4", - "socket.io-parser": "2.3.1" - } - }, - "socket.io-adapter": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", - "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", - "requires": { - "debug": "2.3.3", - "socket.io-parser": "2.3.1" - } - }, - "socket.io-client": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", - "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", - "requires": { - "backo2": "1.0.2", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "2.3.3", - "engine.io-client": "1.8.4", - "has-binary": "0.1.7", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseuri": "0.0.5", - "socket.io-parser": "2.3.1", - "to-array": "0.1.4" - }, - "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - } - } - }, - "socket.io-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", - "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", - "requires": { - "component-emitter": "1.1.2", - "debug": "2.2.0", - "isarray": "0.0.1", - "json3": "3.3.2" - }, - "dependencies": { - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "requires": { - "ms": "0.7.1" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" - } - } - }, - "socketio-auth": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/socketio-auth/-/socketio-auth-0.0.5.tgz", - "integrity": "sha1-BSnIWMvFTDes8BmNkA5EFVPoMqo=", - "requires": { - "debug": "2.3.3", - "lodash": "3.10.1" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" - } - } - }, "sprintf-js": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", @@ -615,24 +179,6 @@ "ansi-regex": "2.1.1" } }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" - }, "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", @@ -670,30 +216,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "ws": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", - "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", - "requires": { - "options": "0.0.6", - "ultron": "1.0.2" - } - }, - "wtf-8": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", - "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" - }, - "xmlhttprequest-ssl": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", - "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" } } } diff --git a/package.json b/package.json index efcb2cb2..fb543b7a 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,11 @@ "main": "index.js", "scripts": { "prepublish": "", - "test": "npm run load:api & npm run test:ng2web", + "test": "npm run load:api & npm run test:ng2web & npm run test:react-web", "pretest": "cd tests/fireloop && npm install && npm install ../../ && npm run build:sdk", "load:api": "cd tests/fireloop && NODE_ENV=ci node server/server", - "test:ng2web": "cd tests/ng2web && npm test" + "test:ng2web": "cd tests/ng2web && npm test", + "test:react-web": "cd tests/react-web && npm test" }, "repository": { "type": "git", @@ -100,8 +101,7 @@ "url": "https://github.com/mean-expert-official/loopback-sdk-builder/issues" }, "dependencies": { - "@mean-expert/loopback-component-realtime": "^1.0.0-beta.8", - "chalk": "^2.1.0", + "chalk": "1.1.3", "ejs": "1.0", "extfs": "0.0.7", "mkdirp": "0.5.1", diff --git a/tests/fireloop/package-lock.json b/tests/fireloop/package-lock.json index 198e3860..5c952c08 100644 --- a/tests/fireloop/package-lock.json +++ b/tests/fireloop/package-lock.json @@ -70,8 +70,7 @@ "@mean-expert/loopback-sdk-builder": { "version": "file:../..", "requires": { - "@mean-expert/loopback-component-realtime": "1.0.0-rc.8.7", - "chalk": "2.1.0", + "chalk": "1.1.3", "ejs": "1.0.0", "extfs": "0.0.7", "mkdirp": "0.5.1", @@ -83,113 +82,21 @@ }, "dependencies": { "@mean-expert/loopback-component-realtime": { - "version": "1.0.0-rc.8.7", - "bundled": true, - "requires": { - "async": "2.4.1", - "chalk": "1.1.3", - "loopback-context": "1.0.0", - "socket.io": "1.7.4", - "socket.io-client": "1.7.4", - "socketio-auth": "0.0.5" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - } - } - }, - "accepts": { - "version": "1.3.3", - "bundled": true, - "requires": { - "mime-types": "2.1.15", - "negotiator": "0.6.1" - } - }, - "after": { - "version": "0.8.2", + "version": "", "bundled": true }, "ansi-regex": { "version": "2.1.1", "bundled": true }, - "ansi-styles": { - "version": "3.2.0", - "bundled": true, - "requires": { - "color-convert": "1.9.0" - } - }, - "arraybuffer.slice": { - "version": "0.0.6", - "bundled": true - }, - "async": { - "version": "2.4.1", - "bundled": true, - "requires": { - "lodash": "4.17.4" - } - }, "async-listener": { - "version": "0.6.5", - "bundled": true, - "requires": { - "semver": "5.3.0", - "shimmer": "1.1.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "bundled": true - } - } - }, - "backo2": { - "version": "1.0.2", + "version": "", "bundled": true }, "balanced-match": { "version": "1.0.0", "bundled": true }, - "base64-arraybuffer": { - "version": "0.1.5", - "bundled": true - }, - "base64id": { - "version": "1.0.0", - "bundled": true - }, - "better-assert": { - "version": "1.0.2", - "bundled": true, - "requires": { - "callsite": "1.0.0" - } - }, - "blob": { - "version": "0.0.4", - "bundled": true - }, "brace-expansion": { "version": "1.1.8", "bundled": true, @@ -198,137 +105,42 @@ "concat-map": "0.0.1" } }, - "callsite": { - "version": "1.0.0", - "bundled": true - }, "chalk": { - "version": "2.1.0", + "version": "1.1.3", "bundled": true, "requires": { - "ansi-styles": "3.2.0", + "ansi-styles": "2.2.1", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" - } - }, - "color-convert": { - "version": "1.9.0", - "bundled": true, - "requires": { - "color-name": "1.1.3" + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } } }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "component-bind": { - "version": "1.0.0", - "bundled": true - }, - "component-emitter": { - "version": "1.1.2", - "bundled": true - }, - "component-inherit": { - "version": "0.0.3", - "bundled": true - }, "concat-map": { "version": "0.0.1", "bundled": true }, - "continuation-local-storage": { - "version": "3.2.0", - "bundled": true, - "requires": { - "async-listener": "0.6.5", - "emitter-listener": "1.0.1" - } - }, - "cookie": { - "version": "0.3.1", - "bundled": true - }, - "debug": { - "version": "2.3.3", - "bundled": true, - "requires": { - "ms": "0.7.2" - } - }, "ejs": { "version": "1.0.0", "bundled": true }, "emitter-listener": { - "version": "1.0.1", - "bundled": true, - "requires": { - "shimmer": "1.0.0" - }, - "dependencies": { - "shimmer": { - "version": "1.0.0", - "bundled": true - } - } - }, - "engine.io": { - "version": "1.8.4", - "bundled": true, - "requires": { - "accepts": "1.3.3", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "ws": "1.1.4" - } + "version": "", + "bundled": true }, "engine.io-client": { - "version": "1.8.4", - "bundled": true, - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parsejson": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "1.1.2", - "xmlhttprequest-ssl": "1.5.3", - "yeast": "0.1.2" - }, - "dependencies": { - "component-emitter": { - "version": "1.2.1", - "bundled": true - }, - "ws": { - "version": "1.1.2", - "bundled": true, - "requires": { - "options": "0.0.6", - "ultron": "1.0.2" - } - } - } - }, - "engine.io-parser": { - "version": "1.3.2", - "bundled": true, - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "0.0.6", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", - "has-binary": "0.1.7", - "wtf-8": "1.0.0" - } + "version": "", + "bundled": true }, "escape-string-regexp": { "version": "1.0.5", @@ -364,25 +176,6 @@ "ansi-regex": "2.1.1" } }, - "has-binary": { - "version": "0.1.7", - "bundled": true, - "requires": { - "isarray": "0.0.1" - } - }, - "has-cors": { - "version": "1.1.0", - "bundled": true - }, - "has-flag": { - "version": "2.0.0", - "bundled": true - }, - "indexof": { - "version": "0.0.1", - "bundled": true - }, "inflight": { "version": "1.0.6", "bundled": true, @@ -395,36 +188,6 @@ "version": "2.0.3", "bundled": true }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "json3": { - "version": "3.3.2", - "bundled": true - }, - "lodash": { - "version": "4.17.4", - "bundled": true - }, - "loopback-context": { - "version": "1.0.0", - "bundled": true, - "requires": { - "continuation-local-storage": "3.2.0" - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "1.27.0" - } - }, "minimatch": { "version": "3.0.4", "bundled": true, @@ -443,22 +206,6 @@ "minimist": "0.0.8" } }, - "ms": { - "version": "0.7.2", - "bundled": true - }, - "negotiator": { - "version": "0.6.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.0", - "bundled": true - }, - "object-component": { - "version": "0.0.3", - "bundled": true - }, "once": { "version": "1.4.0", "bundled": true, @@ -474,31 +221,6 @@ "wordwrap": "0.0.3" } }, - "options": { - "version": "0.0.6", - "bundled": true - }, - "parsejson": { - "version": "0.0.3", - "bundled": true, - "requires": { - "better-assert": "1.0.2" - } - }, - "parseqs": { - "version": "0.0.5", - "bundled": true, - "requires": { - "better-assert": "1.0.2" - } - }, - "parseuri": { - "version": "0.0.5", - "bundled": true, - "requires": { - "better-assert": "1.0.2" - } - }, "path-is-absolute": { "version": "1.0.1", "bundled": true @@ -514,90 +236,17 @@ "version": "5.4.1", "bundled": true }, - "shimmer": { - "version": "1.1.0", - "bundled": true - }, - "socket.io": { - "version": "1.7.4", - "bundled": true, - "requires": { - "debug": "2.3.3", - "engine.io": "1.8.4", - "has-binary": "0.1.7", - "object-assign": "4.1.0", - "socket.io-adapter": "0.5.0", - "socket.io-client": "1.7.4", - "socket.io-parser": "2.3.1" - } - }, - "socket.io-adapter": { - "version": "0.5.0", - "bundled": true, - "requires": { - "debug": "2.3.3", - "socket.io-parser": "2.3.1" - } - }, "socket.io-client": { - "version": "1.7.4", - "bundled": true, - "requires": { - "backo2": "1.0.2", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "2.3.3", - "engine.io-client": "1.8.4", - "has-binary": "0.1.7", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseuri": "0.0.5", - "socket.io-parser": "2.3.1", - "to-array": "0.1.4" - }, - "dependencies": { - "component-emitter": { - "version": "1.2.1", - "bundled": true - } - } + "version": "", + "bundled": true }, "socket.io-parser": { - "version": "2.3.1", - "bundled": true, - "requires": { - "component-emitter": "1.1.2", - "debug": "2.2.0", - "isarray": "0.0.1", - "json3": "3.3.2" - }, - "dependencies": { - "debug": { - "version": "2.2.0", - "bundled": true, - "requires": { - "ms": "0.7.1" - } - }, - "ms": { - "version": "0.7.1", - "bundled": true - } - } + "version": "", + "bundled": true }, "socketio-auth": { - "version": "0.0.5", - "bundled": true, - "requires": { - "debug": "2.3.3", - "lodash": "3.10.1" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "bundled": true - } - } + "version": "", + "bundled": true }, "sprintf-js": { "version": "1.1.1", @@ -610,21 +259,6 @@ "ansi-regex": "2.1.1" } }, - "supports-color": { - "version": "4.4.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - }, - "to-array": { - "version": "0.1.4", - "bundled": true - }, - "ultron": { - "version": "1.0.2", - "bundled": true - }, "underscore": { "version": "1.8.3", "bundled": true @@ -656,26 +290,6 @@ "wrappy": { "version": "1.0.2", "bundled": true - }, - "ws": { - "version": "1.1.4", - "bundled": true, - "requires": { - "options": "0.0.6", - "ultron": "1.0.2" - } - }, - "wtf-8": { - "version": "1.0.0", - "bundled": true - }, - "xmlhttprequest-ssl": { - "version": "1.5.3", - "bundled": true - }, - "yeast": { - "version": "0.1.2", - "bundled": true } } }, diff --git a/tests/fireloop/package.json b/tests/fireloop/package.json index abbd4f66..5fa88307 100644 --- a/tests/fireloop/package.json +++ b/tests/fireloop/package.json @@ -10,8 +10,9 @@ "start": "node server/server.js", "posttest": "npm run lint && nsp check", "test": "NODE_ENV=testing npm run start", - "build:sdk": "npm run build:sdk:ng2web", - "build:sdk:ng2web": "./node_modules/.bin/lb-sdk server/server.js ../ng2web/src/app/shared/sdk -d ng2web -i enabled -w enabled -n orm -v disabled -f disabled" + "build:sdk": "npm run build:sdk:ng2web && npm run build:sdk:react", + "build:sdk:ng2web": "./node_modules/.bin/lb-sdk server/server.js ../ng2web/src/app/shared/sdk -d ng2web -i enabled -w enabled -n orm -v disabled -f disabled", + "build:sdk:react": "./../../bin/lb-sdk server/server.js ./../react-web/app/shared/sdk -i disabled -w enabled -l react -t false" }, "dependencies": { "@mean-expert/boot-script": "^1.0.0", diff --git a/tests/ng2web/package-lock.json b/tests/ng2web/package-lock.json index 32294b19..5c83e7d2 100644 --- a/tests/ng2web/package-lock.json +++ b/tests/ng2web/package-lock.json @@ -5,56 +5,80 @@ "requires": true, "dependencies": { "@angular-devkit/build-optimizer": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.13.tgz", - "integrity": "sha512-yEMkYU4YU8XlA5OauPhg22ZEWJ4X2VhiFKUwfeo4UWJ7lz4XWiuBJocrT5NHWqI1S0rOLpSixLXG9byvFMbavA==", + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.29.tgz", + "integrity": "sha512-ia3EiQ26zU8qxl3PwtqlhClvvPhxy8qMW12KbfKJtqssOu2L+JQZXeWjvjwPkLFpZe5pgk5HvyCRYAMZMbumAQ==", "dev": true, "requires": { "loader-utils": "1.1.0", "source-map": "0.5.7", - "typescript": "2.5.2" + "typescript": "2.5.3", + "webpack-sources": "1.0.1" + } + }, + "@angular-devkit/core": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.0.20.tgz", + "integrity": "sha512-lg5BvMxOfbVD//SOQvpq6TPIKTXYNMj0I9N/kfXbXkUGgiBGFLyFMf2fc+qNvDoa7lulKMPT8OJWS1YlGt93eg==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "@angular-devkit/schematics": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.34.tgz", + "integrity": "sha512-MMi8dAGZNn0MIsOtz4911UE3645SCqUTMTuYBXe/QYg5loGzn7i0dx0AY76bdOTbHbfZ6Edam4mzhU2KwHJy0Q==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.0.20", + "@ngtools/json-schema": "1.1.0", + "minimist": "1.2.0", + "rxjs": "5.5.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, "@angular/cli": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.3.2.tgz", - "integrity": "sha512-VAZXI19PbhhUE/dJH5r6HT7502y0OXYzxhbGIagh/e7SNKnVV8KglVL4zfTfnsI8kmLrFFbAmPy7xomKO8Btkg==", + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.4.9.tgz", + "integrity": "sha512-B3jRygC7MMVAmAD7tvsgCx/54EncEgPqCQfTRQq7nIKLe2dh1yGCxfPkKl94/HU703a1tdJxpLxC+xEn0+v84Q==", "dev": true, "requires": { - "@angular-devkit/build-optimizer": "0.0.13", + "@angular-devkit/build-optimizer": "0.0.29", + "@angular-devkit/schematics": "0.0.34", "@ngtools/json-schema": "1.1.0", - "@ngtools/webpack": "1.6.2", + "@ngtools/webpack": "1.7.4", + "@schematics/angular": "0.0.48", "autoprefixer": "6.7.7", - "chalk": "2.1.0", + "chalk": "2.2.0", "circular-dependency-plugin": "3.0.0", "common-tags": "1.4.0", + "copy-webpack-plugin": "4.2.0", "core-object": "3.1.5", "css-loader": "0.28.7", "cssnano": "3.10.0", "denodeify": "1.2.1", - "diff": "3.3.0", - "ember-cli-normalize-entity-name": "1.0.0", "ember-cli-string-utils": "1.1.0", "exports-loader": "0.6.4", "extract-text-webpack-plugin": "3.0.0", - "file-loader": "0.10.1", - "fs-extra": "4.0.1", - "get-caller-file": "1.0.2", + "file-loader": "1.1.5", + "fs-extra": "4.0.2", "glob": "7.1.2", - "heimdalljs": "0.2.5", - "heimdalljs-logger": "0.1.9", "html-webpack-plugin": "2.30.1", - "inflection": "1.12.0", - "inquirer": "3.2.3", - "isbinaryfile": "3.0.2", "istanbul-instrumenter-loader": "2.0.0", "karma-source-map-support": "1.2.0", "less": "2.7.2", "less-loader": "4.0.5", - "license-webpack-plugin": "0.5.1", + "license-webpack-plugin": "1.1.1", "lodash": "4.17.4", "memory-fs": "0.4.1", - "minimatch": "3.0.4", "node-modules-path": "1.0.1", "node-sass": "4.5.3", "nopt": "4.0.1", @@ -64,26 +88,24 @@ "postcss-url": "5.1.2", "raw-loader": "0.5.1", "resolve": "1.4.0", - "rsvp": "3.6.2", - "rxjs": "5.4.3", + "rxjs": "5.5.0", "sass-loader": "6.0.6", - "script-loader": "0.7.0", "semver": "5.4.1", "silent-error": "1.1.0", - "source-map-loader": "0.2.1", + "source-map-loader": "0.2.3", "source-map-support": "0.4.16", "style-loader": "0.13.2", "stylus": "0.54.5", "stylus-loader": "3.0.1", - "temp": "0.8.3", - "typescript": "2.4.2", - "url-loader": "0.5.9", - "walk-sync": "0.3.2", - "webpack": "3.4.1", + "typescript": "2.5.3", + "url-loader": "0.6.2", + "webpack": "3.7.1", + "webpack-concat-plugin": "1.4.0", "webpack-dev-middleware": "1.12.0", - "webpack-dev-server": "2.5.1", + "webpack-dev-server": "2.7.1", "webpack-merge": "4.1.0", - "zone.js": "0.8.17" + "webpack-sources": "1.0.1", + "zone.js": "0.8.18" }, "dependencies": { "ansi-styles": { @@ -96,14 +118,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -113,45 +135,39 @@ "dev": true }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" } - }, - "typescript": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz", - "integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=", - "dev": true } } }, "@angular/common": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.3.6.tgz", - "integrity": "sha1-7TfpMHx1Bt2DR5fBps9nXlK1tu4=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.6.tgz", + "integrity": "sha1-S4FCByTggooOg5uVpV6xp+g5GPI=", "requires": { "tslib": "1.7.1" } }, "@angular/compiler": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.3.6.tgz", - "integrity": "sha1-vhcN8Ji3HoNczt8WjV+3sj5QRbg=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.6.tgz", + "integrity": "sha1-LuH68lt1fh0SiXkHS+f65SmzvCA=", "requires": { "tslib": "1.7.1" } }, "@angular/compiler-cli": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.3.6.tgz", - "integrity": "sha1-avpq72jdaB5hs5i+TWJw5choCxI=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.6.tgz", + "integrity": "sha1-uv09HiYOmQh+uajPdTLb1gOrubE=", "dev": true, "requires": { - "@angular/tsc-wrapped": "4.3.6", + "@angular/tsc-wrapped": "4.4.6", "minimist": "1.2.0", "reflect-metadata": "0.1.10" }, @@ -165,76 +181,76 @@ } }, "@angular/core": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.3.6.tgz", - "integrity": "sha1-u6xj1o0Pe8s4nRKzQghlK+MofpY=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.6.tgz", + "integrity": "sha1-EwMf0Q3P5DiHVBmzjyESCVi8I1Q=", "requires": { "tslib": "1.7.1" } }, "@angular/forms": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.3.6.tgz", - "integrity": "sha1-DyDEWXwWoVJ0XXzZVVmFWgpcZoc=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.6.tgz", + "integrity": "sha1-/mSs5CQ1wbgPSQNLfEHOjK8UpEo=", "requires": { "tslib": "1.7.1" } }, "@angular/http": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.3.6.tgz", - "integrity": "sha1-Vjgn0afV6J47fYa3f7vTZ7LAhZE=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.6.tgz", + "integrity": "sha1-CvaAxnEL3AJtlA4iXP0PalwAXQw=", "requires": { "tslib": "1.7.1" } }, "@angular/platform-browser": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.3.6.tgz", - "integrity": "sha1-YVKx87eNAkb8XhUOL3ue1DN+O6Y=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.6.tgz", + "integrity": "sha1-qYOcVH4bZU+h0kqJeAyLpquNzOA=", "requires": { "tslib": "1.7.1" } }, "@angular/platform-browser-dynamic": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.3.6.tgz", - "integrity": "sha1-nqv4JvEZyY+Fwqlu3LGKsAtO+xw=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.6.tgz", + "integrity": "sha1-TT2aanvyzz3kBYphWuBZ7/ZB+jY=", "requires": { "tslib": "1.7.1" } }, "@angular/router": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.3.6.tgz", - "integrity": "sha1-ZAM+20/NoIoyPnUztKGCDA8o0TA=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.6.tgz", + "integrity": "sha1-D2rSmuD/jSyeo3m9MgRHIXt+yGY=", "requires": { "tslib": "1.7.1" } }, "@angular/tsc-wrapped": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.3.6.tgz", - "integrity": "sha1-GqZuCrLEeZpK0UtnXhOVOqX81DY=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.6.tgz", + "integrity": "sha1-Fnh8u/UL3H5zgSOxnDJSfyROF40=", "dev": true, "requires": { "tsickle": "0.21.6" } }, "@ngrx/effects": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-4.0.5.tgz", - "integrity": "sha1-EiR2OABiG3MF+bGLwX7gmyXIYdE=" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-4.1.0.tgz", + "integrity": "sha1-pn9au3G9sv6h+pt1Gk84Q1Z0pqg=" }, "@ngrx/router-store": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-4.0.4.tgz", - "integrity": "sha1-q1nzWq6TRlCIOE+vAJ4hsi7dRWo=" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-4.1.0.tgz", + "integrity": "sha1-rHeWnDjEBsxvDRU35+eFAqzgO5o=" }, "@ngrx/store": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-4.0.3.tgz", - "integrity": "sha1-Nqus36Gb+4UG5A3oC64GBQoeFek=" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-4.1.0.tgz", + "integrity": "sha1-jAdMvGGX4lnNlJLoWnbDxn2+oXM=" }, "@ngrx/store-devtools": { "version": "4.0.0", @@ -248,44 +264,66 @@ "dev": true }, "@ngtools/webpack": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.6.2.tgz", - "integrity": "sha512-2s2kCCV3FQUC+MG69e+H5k7zELuVcQ0Gkl1ioqR25HOclxv0UGVY7jsmz9LRm/DanS5ORXQt4S82EFV1dY4w+A==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.7.4.tgz", + "integrity": "sha512-o0u1Oj1k1WEIamBNEncvXDWmUxCMDIlKrMFp4nIwh7bag4dndDShUVD1EinSpx1TvMjVbA42Z+7cIVmlq+240Q==", "dev": true, "requires": { + "enhanced-resolve": "3.4.1", "loader-utils": "1.1.0", "magic-string": "0.22.4", "source-map": "0.5.7" } }, + "@schematics/angular": { + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.0.48.tgz", + "integrity": "sha512-c68ckw4yUbuEM0TTs2Scg5HrDjNPvbiGsoukm5K/fpQ8Ori4lXRLEaIxqnyVpnCV4coUtb1B7/qsBCUR2Cr2SA==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.0.20" + } + }, "@types/jasmine": { - "version": "2.5.54", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.54.tgz", - "integrity": "sha512-B9YofFbUljs19g5gBKUYeLIulsh31U5AK70F41BImQRHEZQGm4GcN922UvnYwkduMqbC/NH+9fruWa/zrqvHIg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.6.0.tgz", + "integrity": "sha512-1ZZdFvYA5zARDXPj5+VF0bwDZWH/o0QQWJVDc5srdC/DngcCZXskR33eR/4PielGvBjLQpQOd6KiQbmtqVkeZA==", "dev": true }, "@types/lodash": { - "version": "4.14.74", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.74.tgz", - "integrity": "sha512-BZknw3E/z3JmCLqQVANcR17okqVTPZdlxvcIz0fJiJVLUCbSH1hK3zs9r634PVSmrzAxN+n/fxlVRiYoArdOIQ==", + "version": "4.14.78", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.78.tgz", + "integrity": "sha512-AflcpYyLyf/VIgSJbG/WMx7Bk00UejtSjYUW176K7erXChVcZENFdgOKOKfOXX9MmcXKoZW1QVFbqYapkhn1rA==", "dev": true }, "@types/node": { - "version": "8.0.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.26.tgz", - "integrity": "sha512-wbKN0MB4XsjdnSE04HiCzLoBDirGCM6zXrqavSj44nZnPFYpnrTF64E9O6Xmf0ca/IuKK/BHUcXwMiwk92gW6Q==", + "version": "8.0.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.46.tgz", + "integrity": "sha512-rRkP4kb5JYIfAoRKaDbcdPZBcTNOgzSApyzhPN9e6rhViSJAWQGlSXIX5gc75iR02jikhpzy3usu31wMHllfFw==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.53.42", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz", + "integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=", "dev": true }, "@types/socket.io-client": { - "version": "1.4.30", - "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.30.tgz", - "integrity": "sha512-iBRrnHweLU2LRd8V3W0fD6z8+t9uEYN/6GPK2awwknKhOt55ZaG08f1sELeWejE6vJCnDvHAjfFkbWRJZ0+DDQ==", + "version": "1.4.31", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.31.tgz", + "integrity": "sha512-CNxZH+ZPL0bkg9qr7HMNHI2TzZOHGbha3LrrH8TIMutd2TUAreb1YJ9u8pfptzZbbBiwnSpZkY+mmrqkZp5I7A==", "dev": true }, "abbrev": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", - "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, "accepts": { @@ -299,9 +337,9 @@ } }, "acorn": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", - "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", + "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==", "dev": true }, "acorn-dynamic-import": { @@ -321,15 +359,39 @@ } } }, + "adm-zip": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "dev": true + }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + } + } + }, "ajv": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", - "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.4.tgz", + "integrity": "sha1-Pa+ai2ciEpn9ro2C0RftjmyAJEs=", "dev": true, "requires": { "co": "4.6.0", @@ -367,12 +429,6 @@ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, - "ansi-escapes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz", - "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=", - "dev": true - }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -417,9 +473,9 @@ } }, "aproba": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", - "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, "are-we-there-yet": { @@ -574,14 +630,6 @@ "bn.js": "4.11.8", "inherits": "2.0.3", "minimalistic-assert": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "assert": { @@ -594,9 +642,9 @@ } }, "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, "async": { @@ -634,17 +682,17 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000721", + "caniuse-db": "1.0.30000749", "normalize-range": "0.1.2", "num2fraction": "1.2.2", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, "aws4": { @@ -808,9 +856,9 @@ } }, "big.js": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz", - "integrity": "sha1-TK2iGTZS6zyp7I5VyQFWacmAaXg=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", "dev": true }, "binary-extensions": { @@ -834,6 +882,23 @@ "inherits": "2.0.3" } }, + "blocking-proxy": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", + "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", + "dev": true, + "requires": { + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "bluebird": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", @@ -908,12 +973,12 @@ "dev": true }, "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "dev": true, "requires": { - "hoek": "2.16.3" + "hoek": "4.2.0" } }, "brace-expansion": { @@ -944,24 +1009,17 @@ "dev": true }, "browserify-aes": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz", - "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", + "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", "dev": true, "requires": { "buffer-xor": "1.0.3", "cipher-base": "1.0.4", "create-hash": "1.1.3", - "evp_bytestokey": "1.0.2", - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.0.1" } }, "browserify-cipher": { @@ -970,9 +1028,9 @@ "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", "dev": true, "requires": { - "browserify-aes": "1.0.6", + "browserify-aes": "1.1.1", "browserify-des": "1.0.0", - "evp_bytestokey": "1.0.2" + "evp_bytestokey": "1.0.3" } }, "browserify-des": { @@ -984,14 +1042,6 @@ "cipher-base": "1.0.4", "des.js": "1.0.0", "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "browserify-rsa": { @@ -1017,14 +1067,6 @@ "elliptic": "6.4.0", "inherits": "2.0.3", "parse-asn1": "5.1.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "browserify-zlib": { @@ -1042,8 +1084,8 @@ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "dev": true, "requires": { - "caniuse-db": "1.0.30000721", - "electron-to-chromium": "1.3.20" + "caniuse-db": "1.0.30000749", + "electron-to-chromium": "1.3.27" } }, "buffer": { @@ -1090,9 +1132,9 @@ "dev": true }, "bytes": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz", - "integrity": "sha1-TJQj6i0lLCcMQbK97+/5u2tiwGo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, "callsite": { @@ -1106,7 +1148,7 @@ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "dev": true, "requires": { - "no-case": "2.3.1", + "no-case": "2.3.2", "upper-case": "1.1.3" } }, @@ -1141,15 +1183,15 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000721", + "caniuse-db": "1.0.30000749", "lodash.memoize": "4.1.2", "lodash.uniq": "4.5.0" } }, "caniuse-db": { - "version": "1.0.30000721", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000721.tgz", - "integrity": "sha1-zcUu/o+C3RORZhW3job3BOzmGAI=", + "version": "1.0.30000749", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000749.tgz", + "integrity": "sha1-VWdzqjqnBPWB10j6Y7RsoIeqxn0=", "dev": true }, "caseless": { @@ -1181,6 +1223,12 @@ "supports-color": "2.0.0" } }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "dev": true + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -1214,14 +1262,6 @@ "requires": { "inherits": "2.0.3", "safe-buffer": "5.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "circular-dependency-plugin": { @@ -1231,38 +1271,23 @@ "dev": true }, "clap": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.0.tgz", - "integrity": "sha1-WckP4+E3EEdG/xlGmiemNP9oyFc=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", "dev": true, "requires": { "chalk": "1.1.3" } }, "clean-css": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.7.tgz", - "integrity": "sha1-ua6k+FZ5iJzz6ui0A0nsTr390DI=", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", + "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", "dev": true, "requires": { "source-map": "0.5.7" } }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", @@ -1312,7 +1337,7 @@ "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", "dev": true, "requires": { - "q": "1.5.0" + "q": "1.5.1" } }, "code-point-at": { @@ -1322,9 +1347,9 @@ "dev": true }, "codelyzer": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-3.1.2.tgz", - "integrity": "sha1-n/HwQfubXuXb60W6hm368EmDrwQ=", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-3.2.2.tgz", + "integrity": "sha512-VNvW9gRThsqRarEnLioiILd0Pdk0yCq/7cVgYvqHpC+3CHqfnrJfmXjoana7vzWfSis+9pODXofjCWX+nlU9Gw==", "dev": true, "requires": { "app-root-path": "2.0.1", @@ -1436,29 +1461,46 @@ "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" }, "compressible": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz", - "integrity": "sha1-FnGKdd4oPtjmBAQWJaIGRYZ5fYo=", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.12.tgz", + "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=", "dev": true, "requires": { - "mime-db": "1.29.0" + "mime-db": "1.30.0" + }, + "dependencies": { + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + } } }, "compression": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz", - "integrity": "sha1-AwyfGY8WQ6BX13anOOki2kNzAS0=", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", + "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", "dev": true, "requires": { "accepts": "1.3.4", - "bytes": "2.5.0", - "compressible": "2.0.11", - "debug": "2.6.8", + "bytes": "3.0.0", + "compressible": "2.0.12", + "debug": "2.6.9", "on-headers": "1.0.1", "safe-buffer": "5.1.1", - "vary": "1.1.1" + "vary": "1.1.2" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -1486,9 +1528,9 @@ } }, "connect-history-api-fallback": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz", - "integrity": "sha1-5R0X+PDvDbkKZP20feMFFVbp8Wk=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.4.0.tgz", + "integrity": "sha1-PbJPlz9LkjsOgvYZzg3wJBHKYj0=", "dev": true }, "console-browserify": { @@ -1542,6 +1584,57 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, + "copy-webpack-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.2.0.tgz", + "integrity": "sha512-eZERim02YjJcepLjrToQMapOoRLfiXewJi9zJON6xXNNJSUhkGzL1L/yFjOufS0KxsnWUzc2szg9t8ZaZKJXAg==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "fs-extra": "4.0.2", + "glob": "7.1.2", + "is-glob": "4.0.0", + "loader-utils": "0.2.17", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "node-dir": "0.1.17" + }, + "dependencies": { + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, "core-js": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", @@ -1553,7 +1646,7 @@ "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", "dev": true, "requires": { - "chalk": "2.1.0" + "chalk": "2.2.0" }, "dependencies": { "ansi-styles": { @@ -1566,14 +1659,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -1583,9 +1676,9 @@ "dev": true }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -1641,15 +1734,7 @@ "cipher-base": "1.0.4", "inherits": "2.0.3", "ripemd160": "2.0.1", - "sha.js": "2.4.8" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } + "sha.js": "2.4.9" } }, "create-hmac": { @@ -1663,15 +1748,7 @@ "inherits": "2.0.3", "ripemd160": "2.0.1", "safe-buffer": "5.0.1", - "sha.js": "2.4.8" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } + "sha.js": "2.4.9" } }, "cross-spawn": { @@ -1685,13 +1762,30 @@ "which": "1.3.0" } }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "dev": true + }, "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "dev": true, "requires": { - "boom": "2.10.1" + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + } } }, "crypto-browserify": { @@ -1707,17 +1801,9 @@ "create-hmac": "1.1.6", "diffie-hellman": "5.0.2", "inherits": "2.0.3", - "pbkdf2": "3.0.13", + "pbkdf2": "3.0.14", "public-encrypt": "4.0.0", "randombytes": "2.0.5" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "css-color-names": { @@ -1739,7 +1825,7 @@ "loader-utils": "1.1.0", "lodash.camelcase": "4.3.0", "object-assign": "4.1.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-modules-extract-imports": "1.1.0", "postcss-modules-local-by-default": "1.2.0", "postcss-modules-scope": "1.1.0", @@ -1809,7 +1895,7 @@ "defined": "1.0.0", "has": "1.0.1", "object-assign": "4.1.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-calc": "5.3.1", "postcss-colormin": "2.2.2", "postcss-convert-values": "2.6.1", @@ -1844,7 +1930,7 @@ "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", "dev": true, "requires": { - "clap": "1.2.0", + "clap": "1.2.3", "source-map": "0.5.7" } }, @@ -1869,7 +1955,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.30" + "es5-ext": "0.10.35" } }, "dashdash": { @@ -1879,14 +1965,6 @@ "dev": true, "requires": { "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "date-now": { @@ -1939,7 +2017,7 @@ "globby": "6.1.0", "is-path-cwd": "1.0.0", "is-path-in-cwd": "1.0.0", - "p-map": "1.1.1", + "p-map": "1.2.0", "pify": "3.0.0", "rimraf": "2.6.1" }, @@ -1984,14 +2062,6 @@ "requires": { "inherits": "2.0.3", "minimalistic-assert": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "destroy": { @@ -2034,7 +2104,7 @@ "dev": true, "requires": { "bn.js": "4.11.8", - "miller-rabin": "4.0.0", + "miller-rabin": "4.0.1", "randombytes": "2.0.5" } }, @@ -2239,10 +2309,16 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "ejs": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", + "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=", + "dev": true + }, "electron-to-chromium": { - "version": "1.3.20", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.20.tgz", - "integrity": "sha1-Lu3VzLrn3cVX9orR/OnBcukV5OU=", + "version": "1.3.27", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz", + "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=", "dev": true }, "elliptic": { @@ -2258,23 +2334,6 @@ "inherits": "2.0.3", "minimalistic-assert": "1.0.0", "minimalistic-crypto-utils": "1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "ember-cli-normalize-entity-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz", - "integrity": "sha1-CxT3vLxZmqEXtf3cgeT9A8S61bc=", - "dev": true, - "requires": { - "silent-error": "1.1.0" } }, "ember-cli-string-utils": { @@ -2367,22 +2426,36 @@ } }, "engine.io-client": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.1.tgz", - "integrity": "sha1-QVqYUrrbFPoAj6PvHjFgjbZ2EyU=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.3.tgz", + "integrity": "sha1-1wXkiYXf6LVKmMn3cFK4sIJYvgU=", "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", - "debug": "2.6.8", + "debug": "2.6.9", "engine.io-parser": "2.1.1", "has-cors": "1.1.0", "indexof": "0.0.1", - "parsejson": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", "ws": "2.3.1", - "xmlhttprequest-ssl": "1.5.3", + "xmlhttprequest-ssl": "1.5.4", "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.4.tgz", + "integrity": "sha1-BPVgkVcks4kIhxXMDteBPpZ3v1c=" + } } }, "engine.io-parser": { @@ -2409,12 +2482,6 @@ "tapable": "0.2.8" } }, - "ensure-posix-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz", - "integrity": "sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI=", - "dev": true - }, "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", @@ -2446,23 +2513,23 @@ } }, "es5-ext": { - "version": "0.10.30", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", - "integrity": "sha1-cUGhaDZpfbq/qq7uQUlc4p9SyTk=", + "version": "0.10.35", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz", + "integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=", "dev": true, "requires": { - "es6-iterator": "2.0.1", + "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } }, "es6-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.30", + "es5-ext": "0.10.35", "es6-symbol": "3.1.1" } }, @@ -2473,13 +2540,19 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", + "es5-ext": "0.10.35", + "es6-iterator": "2.0.3", "es6-set": "0.1.5", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" } }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -2487,8 +2560,8 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", + "es5-ext": "0.10.35", + "es6-iterator": "2.0.3", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" } @@ -2500,7 +2573,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.30" + "es5-ext": "0.10.35" } }, "es6-weak-map": { @@ -2510,8 +2583,8 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", + "es5-ext": "0.10.35", + "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } }, @@ -2568,9 +2641,9 @@ "dev": true }, "etag": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz", - "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE=", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, "event-emitter": { @@ -2580,7 +2653,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.30" + "es5-ext": "0.10.35" } }, "eventemitter3": { @@ -2605,9 +2678,9 @@ } }, "evp_bytestokey": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.2.tgz", - "integrity": "sha512-ni0r0lrm7AOzsh2qC5mi9sj8S0gmj5fLNjfFpxN05FB4tAVZEKotbkjOtLPqTCX/CXT7NsUr6juZb4IFJeNNdA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { "md5.js": "1.3.4", @@ -2650,6 +2723,12 @@ } } }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -2723,39 +2802,41 @@ } }, "express": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz", - "integrity": "sha1-Ay4iU0ic+PzgJma+yj0R7XotrtE=", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", "dev": true, "requires": { "accepts": "1.3.4", "array-flatten": "1.1.1", + "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.2", + "content-type": "1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", - "debug": "2.6.8", + "debug": "2.6.9", "depd": "1.1.1", "encodeurl": "1.0.1", "escape-html": "1.0.3", - "etag": "1.8.0", - "finalhandler": "1.0.4", - "fresh": "0.5.0", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "1.1.2", "on-finished": "2.3.0", - "parseurl": "1.3.1", + "parseurl": "1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "1.1.5", - "qs": "6.5.0", + "proxy-addr": "2.0.2", + "qs": "6.5.1", "range-parser": "1.2.0", - "send": "0.15.4", - "serve-static": "1.12.4", - "setprototypeof": "1.0.3", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", "statuses": "1.3.1", "type-is": "1.6.15", - "utils-merge": "1.0.0", - "vary": "1.1.1" + "utils-merge": "1.0.1", + "vary": "1.1.2" }, "dependencies": { "array-flatten": { @@ -2764,10 +2845,94 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.1", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, "qs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true } } @@ -2778,17 +2943,6 @@ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, - "external-editor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", - "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=", - "dev": true, - "requires": { - "iconv-lite": "0.4.18", - "jschardet": "1.5.1", - "tmp": "0.0.31" - } - }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", @@ -2834,25 +2988,17 @@ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { - "websocket-driver": "0.6.5" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "1.0.5" + "websocket-driver": "0.7.0" } }, "file-loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.10.1.tgz", - "integrity": "sha1-gVA0EZiR/GRB+1pkwRvJPCLd2EI=", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.5.tgz", + "integrity": "sha512-RzGHDatcVNpGISTvCpfUfOGpYuSR7HSsSg87ki+wF6rw1Hm0RALPTiAdsxAq1UwLf0RRhbe22/eHK6nhXspiOQ==", "dev": true, "requires": { - "loader-utils": "1.1.0" + "loader-utils": "1.1.0", + "schema-utils": "0.3.0" } }, "filename-regex": { @@ -2954,9 +3100,9 @@ "dev": true }, "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", "dev": true, "requires": { "asynckit": "0.4.0", @@ -2965,15 +3111,15 @@ } }, "forwarded": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", - "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", "dev": true }, "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, "fs-access": { @@ -2986,13 +3132,13 @@ } }, "fs-extra": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.1.tgz", - "integrity": "sha1-f8DGyJV/mD9X8waiTlud3Y0N2IA=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", "dev": true, "requires": { "graceful-fs": "4.1.11", - "jsonfile": "3.0.1", + "jsonfile": "4.0.0", "universalify": "0.1.1" } }, @@ -3925,7 +4071,7 @@ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "requires": { - "aproba": "1.1.2", + "aproba": "1.2.0", "console-control-strings": "1.1.0", "has-unicode": "2.0.1", "object-assign": "4.1.1", @@ -3933,28 +4079,6 @@ "string-width": "1.0.2", "strip-ansi": "3.0.1", "wide-align": "1.1.2" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } } }, "gaze": { @@ -3992,14 +4116,6 @@ "dev": true, "requires": { "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "glob": { @@ -4116,31 +4232,19 @@ } }, "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", "dev": true }, "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - } + "ajv": "5.2.4", + "har-schema": "2.0.0" } }, "has": { @@ -4210,14 +4314,6 @@ "dev": true, "requires": { "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "hash.js": { @@ -4228,26 +4324,18 @@ "requires": { "inherits": "2.0.3", "minimalistic-assert": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "dev": true, "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.0.2" } }, "he": { @@ -4256,33 +4344,6 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, - "heimdalljs": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz", - "integrity": "sha1-aqVDCO7nk7ZCz/nPlHgURfN3MKw=", - "dev": true, - "requires": { - "rsvp": "3.2.1" - }, - "dependencies": { - "rsvp": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz", - "integrity": "sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo=", - "dev": true - } - } - }, - "heimdalljs-logger": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz", - "integrity": "sha1-12raTkW3u294b8nAEKaOsuL68XY=", - "dev": true, - "requires": { - "debug": "2.6.8", - "heimdalljs": "0.2.5" - } - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -4295,9 +4356,9 @@ } }, "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", "dev": true }, "hosted-git-info": { @@ -4318,12 +4379,6 @@ "wbuf": "1.7.2" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -4375,29 +4430,35 @@ "dev": true }, "html-minifier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.3.tgz", - "integrity": "sha512-iKRzQQDuTCsq0Ultbi/mfJJnR0D3AdZKTq966Gsp92xkmAPCV4Xi08qhJ0Dl3ZAWemSgJ7qZK+UsZc0gFqK6wg==", + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.6.tgz", + "integrity": "sha512-88FjtKrlak2XjczhxrBomgzV4jmGzM3UnHRBScRkJcmcRum0kb+IwhVAETJ8AVp7j0p3xugjSaw9L+RmI5/QOA==", "dev": true, "requires": { "camel-case": "3.0.0", - "clean-css": "4.1.7", + "clean-css": "4.1.9", "commander": "2.11.0", "he": "1.1.1", "ncname": "1.0.0", "param-case": "2.1.1", "relateurl": "0.2.7", - "uglify-js": "3.0.28" + "uglify-js": "3.1.5" }, "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "uglify-js": { - "version": "3.0.28", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.28.tgz", - "integrity": "sha512-0h/qGay016GG2lVav3Kz174F3T2Vjlz2v6HCt+WDQpoXfco0hWwF5gHK9yh88mUYvIC+N7Z8NT8WpjSp1yoqGA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.5.tgz", + "integrity": "sha512-tSqlO7/GZHAVSw6mbtJt2kz0ZcUrKUH7Xg92o52aE+gL0r6cXiASZY4dpHqQ7RVGXmoQuPA2qAkG4TkP59f8XA==", "dev": true, "requires": { "commander": "2.11.0", - "source-map": "0.5.7" + "source-map": "0.6.1" } } } @@ -4409,11 +4470,11 @@ "dev": true, "requires": { "bluebird": "3.5.0", - "html-minifier": "3.5.3", + "html-minifier": "3.5.6", "loader-utils": "0.2.17", "lodash": "4.17.4", "pretty-error": "2.1.1", - "toposort": "1.0.3" + "toposort": "1.0.6" }, "dependencies": { "loader-utils": { @@ -4422,7 +4483,7 @@ "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "dev": true, "requires": { - "big.js": "3.1.3", + "big.js": "3.2.0", "emojis-list": "2.1.0", "json5": "0.5.1", "object-assign": "4.1.1" @@ -4479,6 +4540,12 @@ } } }, + "http-parser-js": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.9.tgz", + "integrity": "sha1-6hoE+2St/wJC6ZdPKX3Uw8rSceE=", + "dev": true + }, "http-proxy": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", @@ -4519,12 +4586,12 @@ } }, "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "0.2.0", + "assert-plus": "1.0.0", "jsprim": "1.4.1", "sshpk": "1.13.1" } @@ -4535,10 +4602,21 @@ "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", "dev": true }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.8", + "extend": "3.0.1" + } + }, "iconv-lite": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", "dev": true }, "icss-replace-symbols": { @@ -4553,7 +4631,7 @@ "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", "dev": true, "requires": { - "postcss": "6.0.10" + "postcss": "6.0.13" }, "dependencies": { "ansi-styles": { @@ -4566,14 +4644,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -4583,20 +4661,26 @@ "dev": true }, "postcss": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.10.tgz", - "integrity": "sha512-7WOpqea/cQHH1XUXdN1mqoFFmhigW3KAXJ+ssMOk/f6mKmwqFgqqdwsnjLGH+wuY+kwaJvT4whHcfKt5kWga0A==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", "dev": true, "requires": { - "chalk": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" + "chalk": "2.2.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -4626,6 +4710,12 @@ "xmldom": "0.1.27" } }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, "in-publish": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", @@ -4653,12 +4743,6 @@ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" }, - "inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4675,93 +4759,25 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "inquirer": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.3.tgz", - "integrity": "sha512-Bc3KbimpDTOeQdDj18Ir/rlsGuhBSSNqdOnxaAuKhpkdnMMuKsEGbZD2v5KFF9oso2OU+BPh7+/u5obmFDRmWw==", - "dev": true, - "requires": { - "ansi-escapes": "2.0.0", - "chalk": "2.1.0", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.0.4", - "figures": "2.0.0", - "lodash": "4.17.4", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.0" - } - }, - "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "dev": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "internal-ip": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", - "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true + }, + "internal-ip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", + "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", "dev": true, "requires": { "meow": "3.7.0" } }, "interpret": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", - "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", + "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", "dev": true }, "intl": { @@ -4791,9 +4807,9 @@ "dev": true }, "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=", "dev": true }, "is-absolute-url": { @@ -4875,10 +4891,13 @@ } }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } }, "is-glob": { "version": "2.0.1", @@ -4949,12 +4968,6 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -5054,7 +5067,7 @@ "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "dev": true, "requires": { - "big.js": "3.1.3", + "big.js": "3.2.0", "emojis-list": "2.1.0", "json5": "0.5.1", "object-assign": "4.1.1" @@ -5137,6 +5150,17 @@ "handlebars": "4.0.10" } }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2", + "jasmine-core": "2.8.0" + } + }, "jasmine-core": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", @@ -5152,10 +5176,16 @@ "colors": "1.1.2" } }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, "js-base64": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz", - "integrity": "sha1-8OgK4DmkvWVLXygfyT8EqRSn/M4=", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", + "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==", "dev": true }, "js-tokens": { @@ -5181,12 +5211,6 @@ "dev": true, "optional": true }, - "jschardet": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz", - "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==", - "dev": true - }, "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", @@ -5239,9 +5263,9 @@ "dev": true }, "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { "graceful-fs": "4.1.11" @@ -5263,13 +5287,52 @@ "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" + } + }, + "jszip": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.4.tgz", + "integrity": "sha512-z6w8iYIxZ/fcgul0j/OerkYnkomH8BZigvzbxVmr2h5HkZUrPtk2kjYtLkqR9wwQxEP6ecKNoKLsbhd18jfnGA==", + "dev": true, + "requires": { + "core-js": "2.3.0", + "es6-promise": "3.0.2", + "lie": "3.1.1", + "pako": "1.0.6", + "readable-stream": "2.0.6" }, "dependencies": { - "assert-plus": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", + "dev": true + }, + "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", "dev": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } } } }, @@ -5432,7 +5495,7 @@ "mime": "1.4.0", "mkdirp": "0.5.1", "promise": "7.3.1", - "request": "2.81.0", + "request": "2.83.0", "source-map": "0.5.7" } }, @@ -5456,12 +5519,21 @@ } }, "license-webpack-plugin": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-0.5.1.tgz", - "integrity": "sha1-aNivEDSGqcTrzt237V071h84O+Q=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-1.1.1.tgz", + "integrity": "sha512-TjKOyiC0exqd4Idy/4M8/DETR22dXBZks387DuS5LbslxHiMRXGx/Q2F/j9IUtvEoH5uFvt72vRgk/G6f8j3Dg==", "dev": true, "requires": { - "object-assign": "4.1.1" + "ejs": "2.5.7" + } + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "dev": true, + "requires": { + "immediate": "3.0.6" } }, "load-json-file": { @@ -5489,7 +5561,7 @@ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", "dev": true, "requires": { - "big.js": "3.1.3", + "big.js": "3.2.0", "emojis-list": "2.1.0", "json5": "0.5.1" } @@ -5579,6 +5651,12 @@ } } }, + "loglevel": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.5.1.tgz", + "integrity": "sha1-GJB4yUq5BT7iFaCs2/JCROoPZQI=", + "dev": true + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -5655,7 +5733,7 @@ "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", "dev": true, "requires": { - "vlq": "0.2.2" + "vlq": "0.2.3" } }, "make-error": { @@ -5670,21 +5748,23 @@ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true }, - "matcher-collection": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz", - "integrity": "sha1-L2auCGmZbynkPQtiyD3R1D5YF1U=", - "dev": true, - "requires": { - "minimatch": "3.0.4" - } - }, "math-expression-evaluator": { "version": "1.2.17", "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", "dev": true }, + "md5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "dev": true, + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "1.1.5" + } + }, "md5.js": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", @@ -5704,12 +5784,6 @@ "inherits": "2.0.3", "safe-buffer": "5.0.1" } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true } } }, @@ -5738,12 +5812,6 @@ "readable-stream": "2.3.3" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5842,9 +5910,9 @@ } }, "miller-rabin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", - "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { "bn.js": "4.11.8", @@ -5961,12 +6029,6 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, "nan": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", @@ -5990,14 +6052,23 @@ "dev": true }, "no-case": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz", - "integrity": "sha1-euuhxzpSGEJlVUt9wDuvcg34AIE=", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "dev": true, "requires": { "lower-case": "1.1.4" } }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, "node-forge": { "version": "0.6.33", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.33.tgz", @@ -6019,7 +6090,7 @@ "nopt": "3.0.6", "npmlog": "4.1.2", "osenv": "0.1.4", - "request": "2.81.0", + "request": "2.83.0", "rimraf": "2.6.1", "semver": "5.3.0", "tar": "2.2.1", @@ -6033,7 +6104,7 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.0" + "abbrev": "1.1.1" } }, "semver": { @@ -6076,12 +6147,6 @@ "vm-browserify": "0.0.4" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6150,7 +6215,7 @@ "nan": "2.7.0", "node-gyp": "3.6.2", "npmlog": "4.1.2", - "request": "2.81.0", + "request": "2.83.0", "sass-graph": "2.2.4", "stdout-stream": "1.4.0" } @@ -6161,7 +6226,7 @@ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "requires": { - "abbrev": "1.1.0", + "abbrev": "1.1.1", "osenv": "0.1.4" } }, @@ -6320,15 +6385,6 @@ "wrappy": "1.0.2" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "1.1.0" - } - }, "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", @@ -6434,9 +6490,9 @@ } }, "p-map": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.1.1.tgz", - "integrity": "sha1-BfXkrpegaDcbwqXMhr+9vBnErno=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, "pako": { @@ -6451,7 +6507,7 @@ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "dev": true, "requires": { - "no-case": "2.3.1" + "no-case": "2.3.2" } }, "parse-asn1": { @@ -6461,10 +6517,10 @@ "dev": true, "requires": { "asn1.js": "4.9.1", - "browserify-aes": "1.0.6", + "browserify-aes": "1.1.1", "create-hash": "1.1.3", - "evp_bytestokey": "1.0.2", - "pbkdf2": "3.0.13" + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" } }, "parse-glob": { @@ -6492,6 +6548,7 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "dev": true, "requires": { "better-assert": "1.0.2" } @@ -6575,22 +6632,22 @@ } }, "pbkdf2": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.13.tgz", - "integrity": "sha512-+dCHxDH+djNtjgWmvVC/my3SYBAKpKNqKSjLkp+GtWWYe4XPE+e/PSD2aCanlEZZnqPk2uekTKNC/ccbwd2X2Q==", + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", "dev": true, "requires": { "create-hash": "1.1.3", "create-hmac": "1.1.6", "ripemd160": "2.0.1", "safe-buffer": "5.0.1", - "sha.js": "2.4.8" + "sha.js": "2.4.9" } }, "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, "phantomjs-prebuilt": { @@ -7347,13 +7404,13 @@ } }, "postcss": { - "version": "5.2.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.17.tgz", - "integrity": "sha1-z09Ze4ZNZcikkrLqvp1wbIecOIs=", + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.1.9", + "js-base64": "2.3.2", "source-map": "0.5.7", "supports-color": "3.2.3" }, @@ -7375,7 +7432,7 @@ "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-message-helpers": "2.0.0", "reduce-css-calc": "1.3.0" } @@ -7387,7 +7444,7 @@ "dev": true, "requires": { "colormin": "1.1.2", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7397,7 +7454,7 @@ "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7407,7 +7464,7 @@ "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-discard-duplicates": { @@ -7416,7 +7473,7 @@ "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-discard-empty": { @@ -7425,7 +7482,7 @@ "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-discard-overridden": { @@ -7434,7 +7491,7 @@ "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-discard-unused": { @@ -7443,7 +7500,7 @@ "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "uniqs": "2.0.0" } }, @@ -7453,7 +7510,7 @@ "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "uniqid": "4.1.1" } }, @@ -7497,7 +7554,7 @@ "requires": { "loader-utils": "1.1.0", "object-assign": "4.1.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-load-config": "1.2.0" } }, @@ -7508,7 +7565,7 @@ "dev": true, "requires": { "has": "1.0.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7518,7 +7575,7 @@ "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-merge-rules": { @@ -7529,7 +7586,7 @@ "requires": { "browserslist": "1.7.7", "caniuse-api": "1.6.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-selector-parser": "2.2.3", "vendors": "1.0.1" } @@ -7547,7 +7604,7 @@ "dev": true, "requires": { "object-assign": "4.1.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7557,7 +7614,7 @@ "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7568,7 +7625,7 @@ "dev": true, "requires": { "alphanum-sort": "1.0.2", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0", "uniqs": "2.0.0" } @@ -7581,7 +7638,7 @@ "requires": { "alphanum-sort": "1.0.2", "has": "1.0.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-selector-parser": "2.2.3" } }, @@ -7591,7 +7648,7 @@ "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", "dev": true, "requires": { - "postcss": "6.0.10" + "postcss": "6.0.13" }, "dependencies": { "ansi-styles": { @@ -7604,14 +7661,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -7621,20 +7678,26 @@ "dev": true }, "postcss": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.10.tgz", - "integrity": "sha512-7WOpqea/cQHH1XUXdN1mqoFFmhigW3KAXJ+ssMOk/f6mKmwqFgqqdwsnjLGH+wuY+kwaJvT4whHcfKt5kWga0A==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", "dev": true, "requires": { - "chalk": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" + "chalk": "2.2.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7649,7 +7712,7 @@ "dev": true, "requires": { "css-selector-tokenizer": "0.7.0", - "postcss": "6.0.10" + "postcss": "6.0.13" }, "dependencies": { "ansi-styles": { @@ -7662,14 +7725,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -7679,20 +7742,26 @@ "dev": true }, "postcss": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.10.tgz", - "integrity": "sha512-7WOpqea/cQHH1XUXdN1mqoFFmhigW3KAXJ+ssMOk/f6mKmwqFgqqdwsnjLGH+wuY+kwaJvT4whHcfKt5kWga0A==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", "dev": true, "requires": { - "chalk": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" + "chalk": "2.2.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7707,7 +7776,7 @@ "dev": true, "requires": { "css-selector-tokenizer": "0.7.0", - "postcss": "6.0.10" + "postcss": "6.0.13" }, "dependencies": { "ansi-styles": { @@ -7720,14 +7789,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -7737,20 +7806,26 @@ "dev": true }, "postcss": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.10.tgz", - "integrity": "sha512-7WOpqea/cQHH1XUXdN1mqoFFmhigW3KAXJ+ssMOk/f6mKmwqFgqqdwsnjLGH+wuY+kwaJvT4whHcfKt5kWga0A==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", "dev": true, "requires": { - "chalk": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" + "chalk": "2.2.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7765,7 +7840,7 @@ "dev": true, "requires": { "icss-replace-symbols": "1.1.0", - "postcss": "6.0.10" + "postcss": "6.0.13" }, "dependencies": { "ansi-styles": { @@ -7778,14 +7853,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -7795,20 +7870,26 @@ "dev": true }, "postcss": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.10.tgz", - "integrity": "sha512-7WOpqea/cQHH1XUXdN1mqoFFmhigW3KAXJ+ssMOk/f6mKmwqFgqqdwsnjLGH+wuY+kwaJvT4whHcfKt5kWga0A==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", "dev": true, "requires": { - "chalk": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" + "chalk": "2.2.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7822,7 +7903,7 @@ "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-normalize-url": { @@ -7833,7 +7914,7 @@ "requires": { "is-absolute-url": "2.1.0", "normalize-url": "1.9.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7843,7 +7924,7 @@ "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7853,7 +7934,7 @@ "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", "dev": true, "requires": { - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7863,7 +7944,7 @@ "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", "dev": true, "requires": { - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-reduce-transforms": { @@ -7873,7 +7954,7 @@ "dev": true, "requires": { "has": "1.0.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0" } }, @@ -7895,7 +7976,7 @@ "dev": true, "requires": { "is-svg": "2.1.0", - "postcss": "5.2.17", + "postcss": "5.2.18", "postcss-value-parser": "3.3.0", "svgo": "0.7.2" } @@ -7907,7 +7988,7 @@ "dev": true, "requires": { "alphanum-sort": "1.0.2", - "postcss": "5.2.17", + "postcss": "5.2.18", "uniqs": "2.0.0" } }, @@ -7918,12 +7999,12 @@ "dev": true, "requires": { "directory-encoder": "0.7.2", - "js-base64": "2.1.9", + "js-base64": "2.3.2", "mime": "1.4.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", "path-is-absolute": "1.0.1", - "postcss": "5.2.17" + "postcss": "5.2.18" } }, "postcss-value-parser": { @@ -7939,7 +8020,7 @@ "dev": true, "requires": { "has": "1.0.1", - "postcss": "5.2.17", + "postcss": "5.2.18", "uniqs": "2.0.0" } }, @@ -7988,44 +8069,32 @@ } }, "protractor": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz", - "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.2.0.tgz", + "integrity": "sha1-0/ObGV6F81Oa2djLZWCp0rYyl8Q=", "dev": true, "requires": { - "@types/node": "6.0.87", + "@types/node": "6.0.90", "@types/q": "0.0.32", "@types/selenium-webdriver": "2.53.42", "blocking-proxy": "0.0.5", "chalk": "1.1.3", "glob": "7.1.2", - "jasmine": "2.7.0", - "jasminewd2": "2.1.0", + "jasmine": "2.8.0", + "jasminewd2": "2.2.0", "optimist": "0.6.1", "q": "1.4.1", "saucelabs": "1.3.0", - "selenium-webdriver": "3.0.1", + "selenium-webdriver": "3.6.0", "source-map-support": "0.4.16", "webdriver-js-extender": "1.0.0", "webdriver-manager": "12.0.6" }, "dependencies": { "@types/node": { - "version": "6.0.87", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.87.tgz", - "integrity": "sha512-Xo0pYENOBaGtJUhi50KH6gdBNQmZQQxAwBArsJpBd15ncoz+LZD5Ev14vuezcw62CsQ1q6bM++7jA6jfwaAbfQ==", - "dev": true - }, - "@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", - "dev": true - }, - "@types/selenium-webdriver": { - "version": "2.53.42", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz", - "integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=", + "version": "6.0.90", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.90.tgz", + "integrity": "sha512-tXoGRVdi7wZX7P1VWoV9Wfk0uYDOAHdEYXAttuWgSrN76Q32wQlSrMX0Rgyv3RTEaQY2ZLQrzYHVM2e8rfo8sA==", "dev": true }, "adm-zip": { @@ -8034,1021 +8103,76 @@ "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", "dev": true }, - "agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "extend": "3.0.1", - "semver": "5.0.3" + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.1" } }, - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", "dev": true }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "webdriver-manager": { + "version": "12.0.6", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", + "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "adm-zip": "0.4.7", + "chalk": "1.1.3", + "del": "2.2.2", + "glob": "7.1.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "q": "1.4.1", + "request": "2.83.0", + "rimraf": "2.6.1", + "semver": "5.4.1", + "xml2js": "0.4.19" } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "blocking-proxy": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", - "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", - "dev": true, - "requires": { - "minimist": "1.2.0" - } - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.1" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.16" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - } - }, - "https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "dev": true, - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.8", - "extend": "3.0.1" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", - "dev": true - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true, - "requires": { - "is-path-inside": "1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", - "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", - "dev": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "jasmine": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.7.0.tgz", - "integrity": "sha1-XPC7TllLRgC7QjVWA2YhKsWuobI=", - "dev": true, - "requires": { - "exit": "0.1.2", - "glob": "7.1.2", - "jasmine-core": "2.7.0" - } - }, - "jasmine-core": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.7.0.tgz", - "integrity": "sha1-UP+MT5LY71wLLBuEbdJj7YUVIJE=", - "dev": true - }, - "jasminewd2": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.1.0.tgz", - "integrity": "sha1-2llSddGuYx3nNqwKfH2Fyfc+9lI=", - "dev": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "mime-db": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", - "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=", - "dev": true - }, - "mime-types": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", - "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", - "dev": true, - "requires": { - "mime-db": "1.29.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - } - } - }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.16", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "rimraf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "saucelabs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", - "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", - "dev": true, - "requires": { - "https-proxy-agent": "1.0.0" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "selenium-webdriver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", - "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", - "dev": true, - "requires": { - "adm-zip": "0.4.7", - "rimraf": "2.6.1", - "tmp": "0.0.30", - "xml2js": "0.4.19" - } - }, - "semver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", - "dev": true - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-support": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.16.tgz", - "integrity": "sha512-A6vlydY7H/ljr4L2UOhDSajQdZQ6dMD7cLH0pzwcmwLyc9u8PNI4WGtnfDDzX7uzGL6c/T+ORL97Zlh+S4iOrg==", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "dev": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", - "dev": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "dev": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "webdriver-js-extender": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", - "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", - "dev": true, - "requires": { - "@types/selenium-webdriver": "2.53.42", - "selenium-webdriver": "2.53.3" - }, - "dependencies": { - "adm-zip": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", - "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", - "dev": true - }, - "sax": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", - "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", - "dev": true - }, - "selenium-webdriver": { - "version": "2.53.3", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", - "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", - "dev": true, - "requires": { - "adm-zip": "0.4.4", - "rimraf": "2.6.1", - "tmp": "0.0.24", - "ws": "1.1.4", - "xml2js": "0.4.4" - } - }, - "tmp": { - "version": "0.0.24", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", - "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", - "dev": true - }, - "xml2js": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", - "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", - "dev": true, - "requires": { - "sax": "0.6.1", - "xmlbuilder": "9.0.4" - } - } - } - }, - "webdriver-manager": { - "version": "12.0.6", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", - "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", - "dev": true, - "requires": { - "adm-zip": "0.4.7", - "chalk": "1.1.3", - "del": "2.2.2", - "glob": "7.1.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "q": "1.4.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.4.1", - "xml2js": "0.4.19" - }, - "dependencies": { - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - } - } - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", - "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", - "dev": true, - "requires": { - "options": "0.0.6", - "ultron": "1.0.2" - } - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dev": true, - "requires": { - "sax": "1.2.4", - "xmlbuilder": "9.0.4" - } - }, - "xmlbuilder": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", - "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=", - "dev": true } } }, "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", "dev": true, "requires": { - "forwarded": "0.1.0", - "ipaddr.js": "1.4.0" + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" } }, "prr": { @@ -9083,9 +8207,9 @@ "dev": true }, "q": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", - "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, "qjobs": { @@ -9379,9 +8503,9 @@ "dev": true }, "regenerate": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz", - "integrity": "sha1-0ZQcZ7rUN+G+dkM63Vs4X5WxkmA=", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", "dev": true }, "regenerator-runtime": { @@ -9406,7 +8530,7 @@ "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { - "regenerate": "1.3.2", + "regenerate": "1.3.3", "regjsgen": "0.2.0", "regjsparser": "0.1.5" } @@ -9481,33 +8605,62 @@ } }, "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "dev": true, "requires": { - "aws-sign2": "0.6.0", + "aws-sign2": "0.7.0", "aws4": "1.6.0", "caseless": "0.12.0", "combined-stream": "1.0.5", "extend": "3.0.1", "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.16", + "mime-types": "2.1.17", "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", "stringstream": "0.0.5", - "tough-cookie": "2.3.2", + "tough-cookie": "2.3.3", "tunnel-agent": "0.6.0", "uuid": "3.1.0" + }, + "dependencies": { + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + } } }, "require-directory": { @@ -9548,16 +8701,6 @@ "path-parse": "1.0.5" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -9584,59 +8727,14 @@ "requires": { "hash-base": "2.0.2", "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "rsvp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", - "dev": true - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "requires": { - "rx-lite": "4.0.8" } }, "rxjs": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz", - "integrity": "sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.0.tgz", + "integrity": "sha512-vmvP5y/oJIJmXKHY36PIjVeI/46Sny6BMBa7/ou2zsNz1PiqU/Gtcz1GujnHz5Qlxncv+J9VlWmttnshqFj3Kg==", "requires": { "symbol-observable": "1.0.4" - }, - "dependencies": { - "symbol-observable": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", - "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" - } } }, "safe-buffer": { @@ -9676,26 +8774,6 @@ "wrap-ansi": "2.1.0" } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, "yargs": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", @@ -9741,6 +8819,15 @@ } } }, + "saucelabs": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", + "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "dev": true, + "requires": { + "https-proxy-agent": "1.0.0" + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -9753,16 +8840,7 @@ "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "dev": true, "requires": { - "ajv": "5.2.2" - } - }, - "script-loader": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.0.tgz", - "integrity": "sha1-aF3H5waeDe56kmdPDrxbD1W6pew=", - "dev": true, - "requires": { - "raw-loader": "0.5.1" + "ajv": "5.2.4" } }, "scss-tokenizer": { @@ -9772,7 +8850,7 @@ "dev": true, "optional": true, "requires": { - "js-base64": "2.1.9", + "js-base64": "2.3.2", "source-map": "0.4.4" }, "dependencies": { @@ -9794,6 +8872,29 @@ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", "dev": true }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "3.1.4", + "rimraf": "2.6.1", + "tmp": "0.0.30", + "xml2js": "0.4.19" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + } + } + }, "selfsigned": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.1.tgz", @@ -9819,59 +8920,108 @@ } }, "send": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz", - "integrity": "sha1-mF+qPihLAnPHkzZKNcZze9k5Bbk=", + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", "dev": true, "requires": { - "debug": "2.6.8", + "debug": "2.6.9", "depd": "1.1.1", "destroy": "1.0.4", "encodeurl": "1.0.1", "escape-html": "1.0.3", - "etag": "1.8.0", - "fresh": "0.5.0", + "etag": "1.8.1", + "fresh": "0.5.2", "http-errors": "1.6.2", - "mime": "1.3.4", + "mime": "1.4.1", "ms": "2.0.0", "on-finished": "2.3.0", "range-parser": "1.2.0", "statuses": "1.3.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", "dev": true } } }, "serve-index": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.0.tgz", - "integrity": "sha1-0rKA/FYNYW7oG0i/D6gqvtJIXOc=", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "requires": { "accepts": "1.3.4", "batch": "0.6.1", - "debug": "2.6.8", + "debug": "2.6.9", "escape-html": "1.0.3", "http-errors": "1.6.2", - "mime-types": "2.1.16", - "parseurl": "1.3.1" + "mime-types": "2.1.17", + "parseurl": "1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + } } }, "serve-static": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz", - "integrity": "sha1-m2qpjutyU8Tu3Ewfb9vKYJkBqWE=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", "dev": true, "requires": { "encodeurl": "1.0.1", "escape-html": "1.0.3", - "parseurl": "1.3.1", - "send": "0.15.4" + "parseurl": "1.3.2", + "send": "0.16.1" + }, + "dependencies": { + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + } } }, "set-blocking": { @@ -9899,20 +9049,13 @@ "dev": true }, "sha.js": { - "version": "2.4.8", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz", - "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=", + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz", + "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==", "dev": true, "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } + "inherits": "2.0.3", + "safe-buffer": "5.0.1" } }, "shallow-clone": { @@ -9975,12 +9118,12 @@ } }, "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", "dev": true, "requires": { - "hoek": "2.16.3" + "hoek": "4.2.0" } }, "socket.io": { @@ -10200,16 +9343,16 @@ } }, "socket.io-client": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.3.tgz", - "integrity": "sha1-bK9K/5+FsZ/ZG2zhPWmttWT4hzs=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", + "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", "requires": { "backo2": "1.0.2", "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", "debug": "2.6.8", - "engine.io-client": "3.1.1", + "engine.io-client": "3.1.3", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", @@ -10249,9 +9392,9 @@ } }, "sockjs-client": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.2.tgz", - "integrity": "sha1-8CEqhVDkyUaMjM6u79LjSTwDOtU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", + "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", "dev": true, "requires": { "debug": "2.6.8", @@ -10268,14 +9411,8 @@ "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", "dev": true, "requires": { - "websocket-driver": "0.6.5" + "websocket-driver": "0.7.0" } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true } } }, @@ -10301,42 +9438,33 @@ "dev": true }, "source-map-loader": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.1.tgz", - "integrity": "sha1-SBJr6SML1H+tBeRqjDwuPS2r5Qc=", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.3.tgz", + "integrity": "sha512-MYbFX9DYxmTQFfy2v8FC1XZwpwHKYxg3SK8Wb7VPBKuhDjz8gi9re2819MsG4p49HDyiOSUKlmZ+nQBArW5CGw==", "dev": true, "requires": { - "async": "0.9.2", + "async": "2.5.0", "loader-utils": "0.2.17", - "source-map": "0.1.43" + "source-map": "0.6.1" }, "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", - "dev": true - }, "loader-utils": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "dev": true, "requires": { - "big.js": "3.1.3", + "big.js": "3.2.0", "emojis-list": "2.1.0", "json5": "0.5.1", "object-assign": "4.1.1" } }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "dev": true, - "requires": { - "amdefine": "1.0.1" - } + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -10399,12 +9527,6 @@ "wbuf": "1.7.2" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -10473,14 +9595,6 @@ "getpass": "0.1.7", "jsbn": "0.1.1", "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "statuses": { @@ -10550,12 +9664,6 @@ "readable-stream": "2.3.3" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -10607,12 +9715,6 @@ "xtend": "4.0.1" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -10664,30 +9766,14 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - } + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "stringstream": { @@ -10772,12 +9858,6 @@ "path-is-absolute": "1.0.1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "sax": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", @@ -10845,6 +9925,11 @@ } } }, + "symbol-observable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", + "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" + }, "tapable": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", @@ -10863,24 +9948,6 @@ "inherits": "2.0.3" } }, - "temp": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", - "dev": true, - "requires": { - "os-tmpdir": "1.0.2", - "rimraf": "2.2.8" - }, - "dependencies": { - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", - "dev": true - } - } - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -10935,15 +10002,15 @@ "dev": true }, "toposort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.3.tgz", - "integrity": "sha1-8CzYp0vYvi/A6YYRw7rLlaFxhpw=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz", + "integrity": "sha1-wxdI5V0hDv/AD9zcfW5o19e7nOw=", "dev": true }, "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", "dev": true, "requires": { "punycode": "1.4.1" @@ -11066,13 +10133,14 @@ "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=" }, "tslint": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", - "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz", + "integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=", "dev": true, "requires": { "babel-code-frame": "6.26.0", - "colors": "1.1.2", + "builtin-modules": "1.1.1", + "chalk": "2.2.0", "commander": "2.11.0", "diff": "3.3.0", "glob": "7.1.2", @@ -11080,13 +10148,50 @@ "resolve": "1.4.0", "semver": "5.4.1", "tslib": "1.7.1", - "tsutils": "2.8.2" + "tsutils": "2.12.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, "tsutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.2.tgz", - "integrity": "sha1-LBSGukMSYIRbCsb5Aq/Z1wio6mo=", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.1.tgz", + "integrity": "sha1-9Nlc4zkciXHkblTEzw7bCiHdWyQ=", "dev": true, "requires": { "tslib": "1.7.1" @@ -11125,9 +10230,9 @@ } }, "typescript": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz", - "integrity": "sha1-A4qV99m7tCCxvzW6MdTFwd0//jQ=", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", "dev": true }, "uglify-js": { @@ -11222,19 +10327,20 @@ } }, "url-loader": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.5.9.tgz", - "integrity": "sha512-B7QYFyvv+fOBqBVeefsxv6koWWtjmHaMFT6KZWti4KRw8YUD/hOU+3AECvXuzyVawIBx3z7zQRejXCDSO5kk1Q==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", + "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", "dev": true, "requires": { "loader-utils": "1.1.0", - "mime": "1.3.6" + "mime": "1.4.1", + "schema-utils": "0.3.0" }, "dependencies": { "mime": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", - "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", "dev": true } } @@ -11342,9 +10448,9 @@ } }, "vary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", - "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, "vendors": { @@ -11362,20 +10468,12 @@ "assert-plus": "1.0.0", "core-util-is": "1.0.2", "extsprintf": "1.3.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "vlq": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.2.tgz", - "integrity": "sha1-4xbVJXtAuGu0PLjV/qXX9U1rDKE=", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", "dev": true }, "vm-browserify": { @@ -11393,16 +10491,6 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, - "walk-sync": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz", - "integrity": "sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ==", - "dev": true, - "requires": { - "ensure-posix-path": "1.0.2", - "matcher-collection": "1.0.4" - } - }, "watchpack": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", @@ -11423,20 +10511,83 @@ "minimalistic-assert": "1.0.0" } }, + "webdriver-js-extender": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", + "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", + "dev": true, + "requires": { + "@types/selenium-webdriver": "2.53.42", + "selenium-webdriver": "2.53.3" + }, + "dependencies": { + "sax": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", + "dev": true + }, + "selenium-webdriver": { + "version": "2.53.3", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", + "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", + "dev": true, + "requires": { + "adm-zip": "0.4.4", + "rimraf": "2.6.1", + "tmp": "0.0.24", + "ws": "1.1.4", + "xml2js": "0.4.4" + } + }, + "tmp": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", + "dev": true + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "ws": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", + "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", + "dev": true, + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + }, + "xml2js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", + "dev": true, + "requires": { + "sax": "0.6.1", + "xmlbuilder": "9.0.4" + } + } + } + }, "webpack": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.4.1.tgz", - "integrity": "sha1-TD9PP7MYFVpNsMtqNv8FxWl0GPQ=", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.7.1.tgz", + "integrity": "sha512-8MR+gVfxsvtx4J1UlbRGkUJEpDQUBFmisRmpPO5cVLgF21R8UMChX39OOjDz63a+m/iswGoqATszdZB2VCsYuA==", "dev": true, "requires": { - "acorn": "5.1.1", + "acorn": "5.1.2", "acorn-dynamic-import": "2.0.2", - "ajv": "5.2.2", + "ajv": "5.2.4", "ajv-keywords": "2.1.0", "async": "2.5.0", "enhanced-resolve": "3.4.1", "escope": "3.6.0", - "interpret": "1.0.3", + "interpret": "1.0.4", "json-loader": "0.5.7", "json5": "0.5.1", "loader-runner": "2.3.0", @@ -11445,7 +10596,7 @@ "mkdirp": "0.5.1", "node-libs-browser": "2.0.0", "source-map": "0.5.7", - "supports-color": "4.4.0", + "supports-color": "4.5.0", "tapable": "0.2.8", "uglifyjs-webpack-plugin": "0.4.6", "watchpack": "1.4.0", @@ -11453,6 +10604,12 @@ "yargs": "8.0.2" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", @@ -11498,15 +10655,6 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -11560,6 +10708,33 @@ "read-pkg": "2.0.0" } }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -11567,9 +10742,9 @@ "dev": true }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -11613,6 +10788,16 @@ } } }, + "webpack-concat-plugin": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/webpack-concat-plugin/-/webpack-concat-plugin-1.4.0.tgz", + "integrity": "sha512-Ym9Qm5Sw9oXJYChNJk09I/yaXDaV3UDxsa07wcCvILzIeSJTnSUZjhS4y2YkULzgE8VHOv9X04KtlJPZGwXqMg==", + "dev": true, + "requires": { + "md5": "2.2.1", + "uglify-js": "2.8.29" + } + }, "webpack-dev-middleware": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz", @@ -11627,27 +10812,29 @@ } }, "webpack-dev-server": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.5.1.tgz", - "integrity": "sha1-oC5yaoe7YD211xq7fW0mSb8Qx2k=", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.7.1.tgz", + "integrity": "sha1-IVgPWgjNBlxxFEz29hw0W8pZqLg=", "dev": true, "requires": { "ansi-html": "0.0.7", "bonjour": "3.5.0", "chokidar": "1.7.0", - "compression": "1.7.0", - "connect-history-api-fallback": "1.3.0", + "compression": "1.7.1", + "connect-history-api-fallback": "1.4.0", "del": "3.0.0", - "express": "4.15.4", + "express": "4.16.2", "html-entities": "1.2.1", "http-proxy-middleware": "0.17.4", "internal-ip": "1.2.0", + "ip": "1.1.5", + "loglevel": "1.5.1", "opn": "4.0.2", "portfinder": "1.0.13", "selfsigned": "1.10.1", - "serve-index": "1.9.0", + "serve-index": "1.9.1", "sockjs": "0.3.18", - "sockjs-client": "1.1.2", + "sockjs-client": "1.1.4", "spdy": "3.4.7", "strip-ansi": "3.0.1", "supports-color": "3.2.3", @@ -11672,15 +10859,6 @@ "wrap-ansi": "2.1.0" } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, "opn": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", @@ -11691,17 +10869,6 @@ "pinkie-promise": "2.0.1" } }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", @@ -11763,18 +10930,19 @@ } }, "websocket-driver": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", - "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "websocket-extensions": "0.1.1" + "http-parser-js": "0.4.9", + "websocket-extensions": "0.1.2" } }, "websocket-extensions": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", - "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.2.tgz", + "integrity": "sha1-Dhh4HeYpoYMIzhSBZQ9n/6JpOl0=", "dev": true }, "when": { @@ -11811,28 +10979,6 @@ "dev": true, "requires": { "string-width": "1.0.2" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } } }, "window-size": { @@ -11855,28 +11001,6 @@ "requires": { "string-width": "1.0.2", "strip-ansi": "3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } } }, "wrappy": { @@ -11906,6 +11030,22 @@ "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=", "dev": true }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.4" + } + }, + "xmlbuilder": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", + "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=", + "dev": true + }, "xmldom": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", @@ -11915,7 +11055,8 @@ "xmlhttprequest-ssl": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", - "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", + "dev": true }, "xtend": { "version": "4.0.1", @@ -11978,9 +11119,9 @@ "dev": true }, "zone.js": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.17.tgz", - "integrity": "sha1-TF5RhahX2o2nk9rzkZNxxaNrKgs=" + "version": "0.8.18", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.18.tgz", + "integrity": "sha512-knKOBQM0oea3/x9pdyDuDi7RhxDlJhOIkeixXSiTKWLgs4LpK37iBc+1HaHwzlciHUKT172CymJFKo8Xgh+44Q==" } } } diff --git a/tests/ng2web/package.json b/tests/ng2web/package.json index 7723bc18..71b9d28e 100644 --- a/tests/ng2web/package.json +++ b/tests/ng2web/package.json @@ -14,35 +14,35 @@ }, "private": true, "dependencies": { - "@angular/common": "^4.3.6", - "@angular/compiler": "^4.3.6", - "@angular/core": "^4.3.6", - "@angular/forms": "^4.3.6", - "@angular/http": "^4.3.6", - "@angular/platform-browser": "^4.3.6", - "@angular/platform-browser-dynamic": "^4.3.6", - "@angular/router": "^4.3.6", - "@ngrx/effects": "^4.0.5", - "@ngrx/router-store": "^4.0.4", - "@ngrx/store": "^4.0.3", + "@angular/common": "^4.4.6", + "@angular/compiler": "^4.4.6", + "@angular/core": "^4.4.6", + "@angular/forms": "^4.4.6", + "@angular/http": "^4.4.6", + "@angular/platform-browser": "^4.4.6", + "@angular/platform-browser-dynamic": "^4.4.6", + "@angular/router": "^4.4.6", + "@ngrx/effects": "^4.1.0", + "@ngrx/router-store": "^4.1.0", + "@ngrx/store": "^4.1.0", "@ngrx/store-devtools": "^4.0.0", "core-js": "^2.5.1", "intl": "^1.2.5", "lodash": "^4.17.4", "loopback-filters": "^0.1.3", "reselect": "^3.0.1", - "rxjs": "^5.1.0", - "socket.io-client": "^2.0.3", - "zone.js": "^0.8.17" + "rxjs": "^5.5.0", + "socket.io-client": "^2.0.4", + "zone.js": "^0.8.18" }, "devDependencies": { - "@angular/cli": "^1.3.2", - "@angular/compiler-cli": "^4.3.6", - "@types/jasmine": "^2.5.54", - "@types/lodash": "^4.14.64", - "@types/node": "^8.0.26", - "@types/socket.io-client": "^1.4.29", - "codelyzer": "^3.1.2", + "@angular/cli": "^1.4.9", + "@angular/compiler-cli": "^4.4.6", + "@types/jasmine": "^2.6.0", + "@types/lodash": "^4.14.78", + "@types/node": "^8.0.46", + "@types/socket.io-client": "^1.4.31", + "codelyzer": "^3.2.2", "jasmine-core": "^2.8.0", "jasmine-spec-reporter": "^4.2.1", "karma": "^1.7.1", @@ -53,9 +53,9 @@ "karma-jasmine-html-reporter": "^0.2.2", "karma-phantomjs-launcher": "^1.0.4", "phantomjs-prebuilt": "^2.1.14", - "protractor": "~5.1.0", + "protractor": "^5.2.0", "ts-node": "^3.3.0", - "tslint": "^5.7.0", - "typescript": "^2.5.2" + "tslint": "^5.8.0", + "typescript": "^2.5.3" } } diff --git a/tests/ng2web/src/app/account.ngrx.spec.ts b/tests/ng2web/src/app/account.ngrx.spec.ts index 45c71318..41209411 100644 --- a/tests/ng2web/src/app/account.ngrx.spec.ts +++ b/tests/ng2web/src/app/account.ngrx.spec.ts @@ -1,5 +1,5 @@ /* tslint:disable:no-unused-variable */ -import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/auditTime'; import { TestBed, async, inject } from '@angular/core/testing'; import { Router } from '@angular/router'; import { StoreModule, Store } from '@ngrx/store'; @@ -21,7 +21,7 @@ const Helpers: { } = { create : function() { const user: Account = new Account(); - user.email = Date.now() + '@test.com'; + user.email = Date.now() + '@account.ngrx'; user.password = 'test'; return user; } @@ -59,7 +59,7 @@ describe('Ngrx: Account', () => { it('should signup and login the user', () => { store.dispatch(new AccountActions.signup(Helpers.create())); store.select(getLoopbackAuthState) - .debounceTime(2000) + .auditTime(2000) .subscribe((token: SDKToken) => { expect(token.id).toBeTruthy(); }); @@ -68,7 +68,7 @@ describe('Ngrx: Account', () => { it('should fail login the user', () => { store.dispatch(new AccountActions.login({ email: 'not@existing.com', password: 'duh' })); store.select(getApplicationState) - .debounceTime(2000) + .auditTime(2000) .subscribe((state: fromApp.IAppState) => { expect((state.error as any).statusCode).toEqual(401); }); diff --git a/tests/ng2web/src/app/account.orm.spec.ts b/tests/ng2web/src/app/account.orm.spec.ts index 63ba3481..88fd056d 100644 --- a/tests/ng2web/src/app/account.orm.spec.ts +++ b/tests/ng2web/src/app/account.orm.spec.ts @@ -1,5 +1,5 @@ /* tslint:disable:no-unused-variable */ -import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/auditTime'; import { TestBed, async, inject } from '@angular/core/testing'; import { Router } from '@angular/router'; import { StoreModule, Store } from '@ngrx/store'; @@ -22,7 +22,7 @@ const Helpers: { } = { create : function() { const user: Account = new Account(); - user.email = Date.now() + '@test.com'; + user.email = Date.now() + '@account.orm'; user.password = 'test'; return user; } @@ -55,7 +55,7 @@ describe('ORM: Account', () => { it('should signup and login the user', () => { orm.Account.signup(Helpers.create()); store.select(getLoopbackAuthState) - .debounceTime(2000) + .auditTime(2000) .subscribe((token: SDKToken) => { expect(token.id).toBeTruthy(); }); @@ -64,7 +64,7 @@ describe('ORM: Account', () => { it('should fail login the user', () => { orm.Account.login({ email: 'not@existing.com', password: 'duh' }); store.select(getApplicationState) - .debounceTime(2000) + .auditTime(2000) .subscribe((state: fromApp.IAppState) => { expect((state.error as any).statusCode).toEqual(401); }); diff --git a/tests/ng2web/src/app/room.ngrx.spec.ts b/tests/ng2web/src/app/room.ngrx.spec.ts index 3a3e8215..39f11d8a 100644 --- a/tests/ng2web/src/app/room.ngrx.spec.ts +++ b/tests/ng2web/src/app/room.ngrx.spec.ts @@ -1,5 +1,5 @@ /* tslint:disable:no-unused-variable */ -import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/auditTime'; import { TestBed, async, inject } from '@angular/core/testing'; import { Router } from '@angular/router'; import { StoreModule, Store } from '@ngrx/store'; @@ -37,24 +37,13 @@ describe('Ngrx: Room', () => { spyOn(store, 'dispatch').and.callThrough(); }); - xit('should contain actions', () => { - expect(RoomActions).toBeTruthy(); - expect(RoomActions.create).toBeTruthy(); - expect(RoomActions.exists).toBeTruthy(); - expect(RoomActions.updateAll).toBeTruthy(); - expect(RoomActions.updateAttributes).toBeTruthy(); - expect(RoomActions.find).toBeTruthy(); - expect(RoomActions.findById).toBeTruthy(); - expect(RoomActions.findOne).toBeTruthy(); - }); - it('should create a new room instance', () => { const room: Room = new Room(); room.name = Date.now().toString(); store.dispatch(new RoomActions.create(room)); store.select(getRooms) - .debounceTime(2000) + .auditTime(2000) .subscribe((rooms: Room[]) => { expect(rooms).toContain(jasmine.objectContaining({name: room.name})); }); @@ -66,7 +55,7 @@ describe('Ngrx: Room', () => { store.dispatch(new RoomActions.create(room)); store.select(getRooms) - .debounceTime(2000) + .auditTime(2000) .subscribe((rooms: Room[]) => { store.select(getRoomById(rooms.filter((r) => r.name === room.name)[0].id)) .subscribe((foundRoom: Room) => { @@ -81,14 +70,14 @@ describe('Ngrx: Room', () => { store.dispatch(new RoomActions.create(room)); store.select(getRooms) - .debounceTime(2000) + .auditTime(2000) .subscribe((rooms: Room[]) => { const createdRoom = rooms.filter((r) => r.name === room.name)[0]; store.dispatch(new RoomActions.updateAttributes(createdRoom.id, { name: 'updated!!!'})); store.select(getRoomById(createdRoom.id)) - .debounceTime(2000) + .auditTime(2000) .subscribe((updatedRoom: Room) => { expect(updatedRoom.id).toBe(createdRoom.id); expect(updatedRoom.name).toBe('updated!!!'); @@ -102,14 +91,14 @@ describe('Ngrx: Room', () => { store.dispatch(new RoomActions.create(room)); store.select(getRooms) - .debounceTime(2000) + .auditTime(2000) .subscribe((rooms: Room[]) => { const createdRoom = rooms.filter((r) => r.name === room.name)[0]; store.dispatch(new RoomActions.patchAttributes(createdRoom.id, { name: 'patched!!!'})); store.select(getRoomById(createdRoom.id)) - .debounceTime(2000) + .auditTime(2000) .subscribe((updatedRoom: Room) => { expect(updatedRoom.id).toBe(createdRoom.id); expect(updatedRoom.name).toBe('patched!!!'); @@ -123,14 +112,14 @@ describe('Ngrx: Room', () => { store.dispatch(new RoomActions.create(room)); store.select(getRooms) - .debounceTime(2000) + .auditTime(2000) .subscribe((rooms: Room[]) => { const createdRoom = rooms.filter((r) => r.name === room.name)[0]; store.dispatch(new RoomActions.createMessages(createdRoom.id, { text: 'HelloRoom'})); store.select(getMessages) - .debounceTime(2000) + .auditTime(2000) .subscribe((messages: Message[]) => { expect(messages).toContain(jasmine.objectContaining({roomId: createdRoom.id, text: 'HelloRoom'})); }); diff --git a/tests/ng2web/src/app/room.orm.spec.ts b/tests/ng2web/src/app/room.orm.spec.ts index ea2ae623..80aecceb 100644 --- a/tests/ng2web/src/app/room.orm.spec.ts +++ b/tests/ng2web/src/app/room.orm.spec.ts @@ -1,17 +1,19 @@ /* tslint:disable:no-unused-variable */ -import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/auditTime'; import { TestBed, async, inject } from '@angular/core/testing'; import { Router } from '@angular/router'; import { StoreModule, Store } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { AppEffects } from './shared/app.effects'; -import { SDKBrowserModule, LoopbackEffects, LoopbackStateInterface, RoomApi, CategoryApi } from './shared/sdk/index'; +import { SDKBrowserModule, LoopbackEffects, LoopbackStateInterface, RoomApi, CategoryApi, getRoomCategorysState } from './shared/sdk/index'; import { Room, Message, Category } from './shared/sdk/models'; import { IAppState, reducerToken, reducerProvider, effects, getApplicationState } from './shared/app.state'; import { OrmModule, Orm } from './shared/sdk/orm'; import * as fromApp from './shared/app.reducer'; +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + class RouterStub { navigate(url: String) { return url; } } @@ -46,7 +48,7 @@ describe('ORM: Room', () => { orm.Room.create(room); orm.Room.find({ where: {name: room.name}}) - .debounceTime(2000) + .auditTime(2000) .subscribe((rooms: Room[]) => { expect(rooms).toContain(jasmine.objectContaining({name: room.name})); }); @@ -58,10 +60,10 @@ describe('ORM: Room', () => { orm.Room.create(room); orm.Room.findOne({ where: {name: room.name}}) - .debounceTime(2000) + .auditTime(2000) .subscribe((createdRoom: Room) => { orm.Room.findById(createdRoom.id) - .debounceTime(2000) + .auditTime(2000) .subscribe((foundRoom: Room) => { expect(foundRoom.name).toBe(room.name); }); @@ -74,12 +76,12 @@ describe('ORM: Room', () => { orm.Room.create(room); orm.Room.findOne({ where: {name: room.name}}) - .debounceTime(2000) + .auditTime(2000) .subscribe((createdRoom: Room) => { orm.Room.updateAttributes(createdRoom.id, Object.assign({}, createdRoom, { name: 'updated!!!'})); orm.Room.findById(createdRoom.id) - .debounceTime(2000) + .auditTime(2000) .subscribe((updatedRoom: Room) => { expect(updatedRoom.id).toBe(createdRoom.id); expect(updatedRoom.name).toBe('updated!!!'); @@ -93,12 +95,12 @@ describe('ORM: Room', () => { orm.Room.create(room); orm.Room.findOne({ where: {name: room.name}}) - .debounceTime(2000) + .auditTime(2000) .subscribe((createdRoom: Room) => { orm.Room.patchAttributes(createdRoom.id, Object.assign({}, createdRoom, { name: 'patched!!!'})); orm.Room.findById(createdRoom.id) - .debounceTime(2000) + .auditTime(2000) .subscribe((updatedRoom: Room) => { expect(updatedRoom.id).toBe(createdRoom.id); expect(updatedRoom.name).toBe('patched!!!'); @@ -112,13 +114,13 @@ describe('ORM: Room', () => { orm.Room.create(room); orm.Room.findOne({ where: {name: room.name}}) - .debounceTime(2000) + .auditTime(2000) .subscribe((createdRoom: Room) => { orm.Room.createMessages(createdRoom.id, { text: 'HelloRoom'}); orm.Room.findById(createdRoom.id, { include: 'messages' }) - .debounceTime(2000) + .auditTime(2000) .subscribe((roomWithMessages: Room) => { expect(roomWithMessages.messages).toContain(jasmine.objectContaining({roomId: createdRoom.id, text: 'HelloRoom'})); }); @@ -131,7 +133,7 @@ describe('ORM: Room', () => { room.name = Date.now().toString(); orm.Room.find({ limit: 5}, {io: true}) - .debounceTime(3000) + .auditTime(3000) .subscribe((rooms: Room[]) => { expect(rooms).toContain(jasmine.objectContaining({name: room.name})); }); @@ -149,7 +151,7 @@ describe('ORM: Room', () => { include: ['messages'], limit: 5 }, {io: true}) - .debounceTime(3000) + .auditTime(3000) .subscribe((rooms: Room[]) => { const roomWithMessages = rooms.filter((r) => r.name === room.name)[0]; expect(rooms).toContain(jasmine.objectContaining({name: room.name})); @@ -158,35 +160,37 @@ describe('ORM: Room', () => { orm.Room.create(room); orm.Room.findOne({ where: {name: room.name}}) - .debounceTime(1000) + .auditTime(1000) .subscribe((createdRoom: Room) => { orm.Room.createMessages(createdRoom.id, { text: 'HelloRoom'}); }); }); - // TODO: ORM support "through" relations - xit('should include linked categories (hasAndBelongsToMany)', + it('should include linked categories (hasAndBelongsToMany)', async(inject([CategoryApi, RoomApi], (categoryApi: CategoryApi, roomApi: RoomApi) => { const category: Category = new Category(); const room: Room = new Room(); room.name = Date.now().toString(); category.name = Date.now().toString(); - roomApi.create(room) + return roomApi.create(room) + .take(1) .subscribe((roomInstance: Room) => categoryApi.create(category) + .take(1) .subscribe((categoryInstance: Category) => categoryApi.linkRooms(categoryInstance.id, roomInstance.id) - .subscribe((result: any) => {}))) - - return orm.Room.findOne({ - where: {name: room.name}, - include: ['categories'] - }) - .debounceTime(3000) - .subscribe((roomWithCategories: Room) => { - expect(roomWithCategories.name).toBe(room.name); - console.log(roomWithCategories); - expect(roomWithCategories.categories).toContain(jasmine.objectContaining({roomId: roomWithCategories.id, name: category.name})); - }); + .take(1) + .subscribe((result: any) => { + orm.Room.findOne({ + where: {name: room.name}, + include: ['categories'] + }) + .auditTime(2000) + .subscribe((roomWithCategories: Room) => { + expect(roomWithCategories.name).toBe(room.name); + console.log(roomWithCategories); + expect(roomWithCategories.categories).toContain(jasmine.objectContaining({name: category.name})); + }); + }))) }) )); }); diff --git a/tests/ng2web/src/app/shared/sdk/effects/Account.ts b/tests/ng2web/src/app/shared/sdk/effects/Account.ts index b4dbff4a..2d612de0 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Account.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Account.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { AccountActionTypes, AccountActions } from '../actions/Account'; import { LoopbackErrorActions } from '../actions/error'; import { AccountApi } from '../services/index'; @@ -103,7 +104,10 @@ export class AccountEffects extends BaseLoopbackEffects { .ofType(AccountActionTypes.LINK_ROOMS) .mergeMap((action: LoopbackAction) => this.account.linkRooms(action.payload.id, action.payload.fk, action.payload.data) - .map((response: any) => new AccountActions.linkRoomsSuccess(action.payload.id, response, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAccountActions'].createSuccess(response, action.meta)), + of(new AccountActions.linkRoomsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new AccountActions.linkRoomsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -115,7 +119,10 @@ export class AccountEffects extends BaseLoopbackEffects { .ofType(AccountActionTypes.UNLINK_ROOMS) .mergeMap((action: LoopbackAction) => this.account.unlinkRooms(action.payload.id, action.payload.fk) - .map((response: any) => new AccountActions.unlinkRoomsSuccess(action.payload.id, action.payload.fk, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAccountActions'].deleteByIdSuccess(response.id, action.meta)), + of(new AccountActions.unlinkRoomsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new AccountActions.unlinkRoomsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -172,7 +179,10 @@ export class AccountEffects extends BaseLoopbackEffects { .ofType(AccountActionTypes.LINK_ADMINISTRATIONS) .mergeMap((action: LoopbackAction) => this.account.linkAdministrations(action.payload.id, action.payload.fk, action.payload.data) - .map((response: any) => new AccountActions.linkAdministrationsSuccess(action.payload.id, response, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAdminActions'].createSuccess(response, action.meta)), + of(new AccountActions.linkAdministrationsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new AccountActions.linkAdministrationsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -184,7 +194,10 @@ export class AccountEffects extends BaseLoopbackEffects { .ofType(AccountActionTypes.UNLINK_ADMINISTRATIONS) .mergeMap((action: LoopbackAction) => this.account.unlinkAdministrations(action.payload.id, action.payload.fk) - .map((response: any) => new AccountActions.unlinkAdministrationsSuccess(action.payload.id, action.payload.fk, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAdminActions'].deleteByIdSuccess(response.id, action.meta)), + of(new AccountActions.unlinkAdministrationsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new AccountActions.unlinkAdministrationsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) diff --git a/tests/ng2web/src/app/shared/sdk/effects/ApplicationCredential.ts b/tests/ng2web/src/app/shared/sdk/effects/ApplicationCredential.ts index 5950a7be..588d0dc0 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/ApplicationCredential.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/ApplicationCredential.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { ApplicationCredentialActionTypes, ApplicationCredentialActions } from '../actions/ApplicationCredential'; import { LoopbackErrorActions } from '../actions/error'; import { ApplicationCredentialApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/Category.ts b/tests/ng2web/src/app/shared/sdk/effects/Category.ts index ac177a79..dca59337 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Category.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Category.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { CategoryActionTypes, CategoryActions } from '../actions/Category'; import { LoopbackErrorActions } from '../actions/error'; import { CategoryApi } from '../services/index'; @@ -67,7 +68,10 @@ export class CategoryEffects extends BaseLoopbackEffects { .ofType(CategoryActionTypes.LINK_ROOMS) .mergeMap((action: LoopbackAction) => this.category.linkRooms(action.payload.id, action.payload.fk, action.payload.data) - .map((response: any) => new CategoryActions.linkRoomsSuccess(action.payload.id, response, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomCategoryActions'].createSuccess(response, action.meta)), + of(new CategoryActions.linkRoomsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new CategoryActions.linkRoomsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -79,7 +83,10 @@ export class CategoryEffects extends BaseLoopbackEffects { .ofType(CategoryActionTypes.UNLINK_ROOMS) .mergeMap((action: LoopbackAction) => this.category.unlinkRooms(action.payload.id, action.payload.fk) - .map((response: any) => new CategoryActions.unlinkRoomsSuccess(action.payload.id, action.payload.fk, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomCategoryActions'].deleteByIdSuccess(response.id, action.meta)), + of(new CategoryActions.unlinkRoomsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new CategoryActions.unlinkRoomsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) diff --git a/tests/ng2web/src/app/shared/sdk/effects/Core.ts b/tests/ng2web/src/app/shared/sdk/effects/Core.ts index 6b51e5e2..74c8d1ba 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Core.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Core.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { CoreActionTypes, CoreActions } from '../actions/Core'; import { LoopbackErrorActions } from '../actions/error'; import { CoreApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/Like.ts b/tests/ng2web/src/app/shared/sdk/effects/Like.ts index d42baa96..b541aefe 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Like.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Like.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { LikeActionTypes, LikeActions } from '../actions/Like'; import { LoopbackErrorActions } from '../actions/error'; import { LikeApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/Message.ts b/tests/ng2web/src/app/shared/sdk/effects/Message.ts index fc56a874..2ff594f2 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Message.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Message.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { MessageActionTypes, MessageActions } from '../actions/Message'; import { LoopbackErrorActions } from '../actions/error'; import { MessageApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/Room.ts b/tests/ng2web/src/app/shared/sdk/effects/Room.ts index e4b9f654..ad6754ac 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Room.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Room.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { RoomActionTypes, RoomActions } from '../actions/Room'; import { LoopbackErrorActions } from '../actions/error'; import { RoomApi } from '../services/index'; @@ -157,7 +158,10 @@ export class RoomEffects extends BaseLoopbackEffects { .ofType(RoomActionTypes.LINK_CATEGORIES) .mergeMap((action: LoopbackAction) => this.room.linkCategories(action.payload.id, action.payload.fk, action.payload.data) - .map((response: any) => new RoomActions.linkCategoriesSuccess(action.payload.id, response, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomCategoryActions'].createSuccess(response, action.meta)), + of(new RoomActions.linkCategoriesSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new RoomActions.linkCategoriesFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -169,7 +173,10 @@ export class RoomEffects extends BaseLoopbackEffects { .ofType(RoomActionTypes.UNLINK_CATEGORIES) .mergeMap((action: LoopbackAction) => this.room.unlinkCategories(action.payload.id, action.payload.fk) - .map((response: any) => new RoomActions.unlinkCategoriesSuccess(action.payload.id, action.payload.fk, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomCategoryActions'].deleteByIdSuccess(response.id, action.meta)), + of(new RoomActions.unlinkCategoriesSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new RoomActions.unlinkCategoriesFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -226,7 +233,10 @@ export class RoomEffects extends BaseLoopbackEffects { .ofType(RoomActionTypes.LINK_ACCOUNTS) .mergeMap((action: LoopbackAction) => this.room.linkAccounts(action.payload.id, action.payload.fk, action.payload.data) - .map((response: any) => new RoomActions.linkAccountsSuccess(action.payload.id, response, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAccountActions'].createSuccess(response, action.meta)), + of(new RoomActions.linkAccountsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new RoomActions.linkAccountsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -238,7 +248,10 @@ export class RoomEffects extends BaseLoopbackEffects { .ofType(RoomActionTypes.UNLINK_ACCOUNTS) .mergeMap((action: LoopbackAction) => this.room.unlinkAccounts(action.payload.id, action.payload.fk) - .map((response: any) => new RoomActions.unlinkAccountsSuccess(action.payload.id, action.payload.fk, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAccountActions'].deleteByIdSuccess(response.id, action.meta)), + of(new RoomActions.unlinkAccountsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new RoomActions.unlinkAccountsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -295,7 +308,10 @@ export class RoomEffects extends BaseLoopbackEffects { .ofType(RoomActionTypes.LINK_ADMINS) .mergeMap((action: LoopbackAction) => this.room.linkAdmins(action.payload.id, action.payload.fk, action.payload.data) - .map((response: any) => new RoomActions.linkAdminsSuccess(action.payload.id, response, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAdminActions'].createSuccess(response, action.meta)), + of(new RoomActions.linkAdminsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new RoomActions.linkAdminsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) @@ -307,7 +323,10 @@ export class RoomEffects extends BaseLoopbackEffects { .ofType(RoomActionTypes.UNLINK_ADMINS) .mergeMap((action: LoopbackAction) => this.room.unlinkAdmins(action.payload.id, action.payload.fk) - .map((response: any) => new RoomActions.unlinkAdminsSuccess(action.payload.id, action.payload.fk, action.meta)) + .mergeMap((response: any) => concat( + of(new actions['RoomAdminActions'].deleteByIdSuccess(response.id, action.meta)), + of(new RoomActions.unlinkAdminsSuccess(action.payload.id, response, action.meta)) + )) .catch((error: any) => concat( of(new RoomActions.unlinkAdminsFail(error, action.meta)), of(new LoopbackErrorActions.error(error, action.meta)) diff --git a/tests/ng2web/src/app/shared/sdk/effects/RoomAccount.ts b/tests/ng2web/src/app/shared/sdk/effects/RoomAccount.ts index 6aeac5a5..022f8e8b 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/RoomAccount.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/RoomAccount.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { RoomAccountActionTypes, RoomAccountActions } from '../actions/RoomAccount'; import { LoopbackErrorActions } from '../actions/error'; import { RoomAccountApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/RoomAdmin.ts b/tests/ng2web/src/app/shared/sdk/effects/RoomAdmin.ts index 5c7afa7c..50ad14af 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/RoomAdmin.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/RoomAdmin.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { RoomAdminActionTypes, RoomAdminActions } from '../actions/RoomAdmin'; import { LoopbackErrorActions } from '../actions/error'; import { RoomAdminApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/Storage.ts b/tests/ng2web/src/app/shared/sdk/effects/Storage.ts index e9556416..ff7c88b4 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/Storage.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/Storage.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { StorageActionTypes, StorageActions } from '../actions/Storage'; import { LoopbackErrorActions } from '../actions/error'; import { StorageApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/User.ts b/tests/ng2web/src/app/shared/sdk/effects/User.ts index cc4cfe43..defc1f8f 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/User.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/User.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { UserActionTypes, UserActions } from '../actions/User'; import { LoopbackErrorActions } from '../actions/error'; import { UserApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/UserCredential.ts b/tests/ng2web/src/app/shared/sdk/effects/UserCredential.ts index f7d39e38..5f10eaf9 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/UserCredential.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/UserCredential.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { UserCredentialActionTypes, UserCredentialActions } from '../actions/UserCredential'; import { LoopbackErrorActions } from '../actions/error'; import { UserCredentialApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/effects/UserIdentity.ts b/tests/ng2web/src/app/shared/sdk/effects/UserIdentity.ts index 6251923e..a1bd34f2 100644 --- a/tests/ng2web/src/app/shared/sdk/effects/UserIdentity.ts +++ b/tests/ng2web/src/app/shared/sdk/effects/UserIdentity.ts @@ -11,6 +11,7 @@ import { LoopbackAction } from '../models/BaseModels'; import { BaseLoopbackEffects } from './base'; import { resolver } from './resolver'; +import * as actions from '../actions'; import { UserIdentityActionTypes, UserIdentityActions } from '../actions/UserIdentity'; import { LoopbackErrorActions } from '../actions/error'; import { UserIdentityApi } from '../services/index'; diff --git a/tests/ng2web/src/app/shared/sdk/lb.config.ts b/tests/ng2web/src/app/shared/sdk/lb.config.ts index 425f7ae8..9618c164 100644 --- a/tests/ng2web/src/app/shared/sdk/lb.config.ts +++ b/tests/ng2web/src/app/shared/sdk/lb.config.ts @@ -26,6 +26,7 @@ export class LoopBackConfig { private static debug: boolean = true; private static filterOn: string = 'headers'; private static secure: boolean = false; + private static withCredentials: boolean = false; public static setApiVersion(version: string = 'api'): void { LoopBackConfig.version = version; @@ -82,4 +83,12 @@ export class LoopBackConfig { public static isSecureWebSocketsSet(): boolean { return LoopBackConfig.secure; } + + public static setRequestOptionsCredentials(withCredentials: boolean = false): void { + LoopBackConfig.withCredentials = withCredentials; + } + + public static getRequestOptionsCredentials(): boolean { + return LoopBackConfig.withCredentials; + } } diff --git a/tests/ng2web/src/app/shared/sdk/orm/base.ts b/tests/ng2web/src/app/shared/sdk/orm/base.ts index 6d9e9b01..8be74753 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/base.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/base.ts @@ -30,7 +30,9 @@ export class OrmBase { }) , filter, this.store, this.model); } else { - this.store.dispatch(new this.actions.find(filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.find(filter, meta)); + } return applyFilter( this.store.select(this.model.getModelName() + 's') @@ -59,7 +61,9 @@ export class OrmBase { return data[0]; }); } else { - this.store.dispatch(new this.actions.findById(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findById(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelName() + 's') @@ -89,7 +93,9 @@ export class OrmBase { return data[0]; }); } else { - this.store.dispatch(new this.actions.findOne(filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findOne(filter, meta)); + } return applyFilter( this.store.select(this.model.getModelName() + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/filter.ts b/tests/ng2web/src/app/shared/sdk/orm/filter.ts index 91c5d20f..7e7b6cfc 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/filter.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/filter.ts @@ -2,6 +2,7 @@ import 'rxjs/add/operator/publishReplay'; import 'rxjs/add/operator/combineLatest'; import 'rxjs/add/operator/withLatestFrom'; +import 'rxjs/add/operator/auditTime'; import { Observable } from 'rxjs/Observable'; import * as filterNodes from 'loopback-filters'; @@ -59,7 +60,7 @@ function include(state$: Observable, filter: LoopBackFilter, store: any, mo const includesArray: any[] = []; - for (const include of normalizedInclude) { + for (let include of normalizedInclude) { let relationSchema: any; if (isPlainObject(include)) { relationSchema = model.getModelDefinition().relations[include.relation]; @@ -69,6 +70,14 @@ function include(state$: Observable, filter: LoopBackFilter, store: any, mo if (!!relationSchema.model) { if (relationSchema.modelThrough) { + if (include.scope && include.scope.fields) { + include = Object.assign({}, include, { + scope: Object.assign({}, include.scope, { + fields: Array.isArray(include.scope.fields) ? [...include.scope.fields, '_through'] : [include.scope.fields, '_through'] + }) + }) + } + includesArray.push( applyFilter( store.select(relationSchema.model + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/Account.ts b/tests/ng2web/src/app/shared/sdk/orm/models/Account.ts index 690b30fb..c99de93c 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/Account.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/Account.ts @@ -34,7 +34,9 @@ export class OrmAccount extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdAccessTokens(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdAccessTokens(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.accessTokens.model + 's') .map((state: any) => state.entities[fk]); @@ -64,7 +66,9 @@ export class OrmAccount extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdRooms(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdRooms(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.rooms.model + 's') .map((state: any) => state.entities[fk]); @@ -102,7 +106,9 @@ export class OrmAccount extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdAdministrations(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdAdministrations(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.administrations.model + 's') .map((state: any) => state.entities[fk]); @@ -143,7 +149,9 @@ export class OrmAccount extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.accessTokens.model]); } else { - this.store.dispatch(new this.actions.getAccessTokens(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAccessTokens(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.accessTokens.model + 's') @@ -179,7 +187,9 @@ export class OrmAccount extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.rooms.model]); } else { - this.store.dispatch(new this.actions.getRooms(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getRooms(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.rooms.model + 's') @@ -215,7 +225,9 @@ export class OrmAccount extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.administrations.model]); } else { - this.store.dispatch(new this.actions.getAdministrations(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAdministrations(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.administrations.model + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/Category.ts b/tests/ng2web/src/app/shared/sdk/orm/models/Category.ts index f33ca73b..814592c2 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/Category.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/Category.ts @@ -34,7 +34,9 @@ export class OrmCategory extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdRooms(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdRooms(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.rooms.model + 's') .map((state: any) => state.entities[fk]); @@ -75,7 +77,9 @@ export class OrmCategory extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.rooms.model]); } else { - this.store.dispatch(new this.actions.getRooms(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getRooms(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.rooms.model + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/Like.ts b/tests/ng2web/src/app/shared/sdk/orm/models/Like.ts index ccc96c5f..f23c0486 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/Like.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/Like.ts @@ -34,7 +34,9 @@ export class OrmLike extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getMessage(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getMessage(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.message.model + 's') .map((state: any) => state.entities[id]); @@ -56,7 +58,9 @@ export class OrmLike extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.room.model + 's') .map((state: any) => state.entities[id]); diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/Message.ts b/tests/ng2web/src/app/shared/sdk/orm/models/Message.ts index b9e79bc7..47ed1580 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/Message.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/Message.ts @@ -34,7 +34,9 @@ export class OrmMessage extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdLikes(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdLikes(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.likes.model + 's') .map((state: any) => state.entities[fk]); @@ -64,7 +66,9 @@ export class OrmMessage extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdReplies(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdReplies(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.replies.model + 's') .map((state: any) => state.entities[fk]); @@ -94,7 +98,9 @@ export class OrmMessage extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getParent(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getParent(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.parent.model + 's') .map((state: any) => state.entities[id]); @@ -116,7 +122,9 @@ export class OrmMessage extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.room.model + 's') .map((state: any) => state.entities[id]); @@ -141,7 +149,9 @@ export class OrmMessage extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.likes.model]); } else { - this.store.dispatch(new this.actions.getLikes(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getLikes(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.likes.model + 's') @@ -177,7 +187,9 @@ export class OrmMessage extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.replies.model]); } else { - this.store.dispatch(new this.actions.getReplies(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getReplies(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.replies.model + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/Room.ts b/tests/ng2web/src/app/shared/sdk/orm/models/Room.ts index 226444a8..2fba70cf 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/Room.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/Room.ts @@ -34,7 +34,9 @@ export class OrmRoom extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdMessages(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdMessages(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.messages.model + 's') .map((state: any) => state.entities[fk]); @@ -64,7 +66,9 @@ export class OrmRoom extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdLikes(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdLikes(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.likes.model + 's') .map((state: any) => state.entities[fk]); @@ -94,7 +98,9 @@ export class OrmRoom extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdCategories(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdCategories(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.categories.model + 's') .map((state: any) => state.entities[fk]); @@ -132,7 +138,9 @@ export class OrmRoom extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdAccounts(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdAccounts(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.accounts.model + 's') .map((state: any) => state.entities[fk]); @@ -170,7 +178,9 @@ export class OrmRoom extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdAdmins(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdAdmins(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.admins.model + 's') .map((state: any) => state.entities[fk]); @@ -211,7 +221,9 @@ export class OrmRoom extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.messages.model]); } else { - this.store.dispatch(new this.actions.getMessages(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getMessages(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.messages.model + 's') @@ -247,7 +259,9 @@ export class OrmRoom extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.likes.model]); } else { - this.store.dispatch(new this.actions.getLikes(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getLikes(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.likes.model + 's') @@ -283,7 +297,9 @@ export class OrmRoom extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.categories.model]); } else { - this.store.dispatch(new this.actions.getCategories(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getCategories(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.categories.model + 's') @@ -319,7 +335,9 @@ export class OrmRoom extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.accounts.model]); } else { - this.store.dispatch(new this.actions.getAccounts(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAccounts(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.accounts.model + 's') @@ -355,7 +373,9 @@ export class OrmRoom extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.admins.model]); } else { - this.store.dispatch(new this.actions.getAdmins(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAdmins(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.admins.model + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/RoomAccount.ts b/tests/ng2web/src/app/shared/sdk/orm/models/RoomAccount.ts index 892b87ae..de36f8fb 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/RoomAccount.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/RoomAccount.ts @@ -34,7 +34,9 @@ export class OrmRoomAccount extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getAccount(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAccount(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.account.model + 's') .map((state: any) => state.entities[id]); @@ -56,7 +58,9 @@ export class OrmRoomAccount extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.room.model + 's') .map((state: any) => state.entities[id]); diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/RoomAdmin.ts b/tests/ng2web/src/app/shared/sdk/orm/models/RoomAdmin.ts index 102e8840..65f4c93d 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/RoomAdmin.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/RoomAdmin.ts @@ -34,7 +34,9 @@ export class OrmRoomAdmin extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getAccount(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAccount(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.account.model + 's') .map((state: any) => state.entities[id]); @@ -56,7 +58,9 @@ export class OrmRoomAdmin extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getRoom(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.room.model + 's') .map((state: any) => state.entities[id]); diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/User.ts b/tests/ng2web/src/app/shared/sdk/orm/models/User.ts index 4362a9b7..09a52e80 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/User.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/User.ts @@ -34,7 +34,9 @@ export class OrmUser extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.findByIdAccessTokens(id, fk, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.findByIdAccessTokens(id, fk, meta)); + } return this.store.select(this.model.getModelDefinition().relations.accessTokens.model + 's') .map((state: any) => state.entities[fk]); @@ -67,7 +69,9 @@ export class OrmUser extends OrmBase { }) , filter, this.store, models[this.model.getModelDefinition().relations.accessTokens.model]); } else { - this.store.dispatch(new this.actions.getAccessTokens(id, filter, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getAccessTokens(id, filter, meta)); + } return applyFilter( this.store.select(this.model.getModelDefinition().relations.accessTokens.model + 's') diff --git a/tests/ng2web/src/app/shared/sdk/orm/models/UserIdentity.ts b/tests/ng2web/src/app/shared/sdk/orm/models/UserIdentity.ts index c16bf1ed..f1312fef 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/models/UserIdentity.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/models/UserIdentity.ts @@ -34,7 +34,9 @@ export class OrmUserIdentity extends OrmBase { destroyStream$.complete(); }); } else { - this.store.dispatch(new this.actions.getUser(id, refresh, meta)); + if (!meta || !meta.justCache) { + this.store.dispatch(new this.actions.getUser(id, refresh, meta)); + } return this.store.select(this.model.getModelDefinition().relations.user.model + 's') .map((state: any) => state.entities[id]); diff --git a/tests/ng2web/src/app/shared/sdk/orm/orm.ts b/tests/ng2web/src/app/shared/sdk/orm/orm.ts index e701cab6..0095b4aa 100644 --- a/tests/ng2web/src/app/shared/sdk/orm/orm.ts +++ b/tests/ng2web/src/app/shared/sdk/orm/orm.ts @@ -24,7 +24,7 @@ export class Orm { public UserCredential: OrmModels.OrmUserCredential; public UserIdentity: OrmModels.OrmUserIdentity; - constructor(private store: Store, protected realTime?: RealTime) { + constructor(public store: Store, protected realTime?: RealTime) { this.User = new OrmModels.OrmUser(store, realTime); this.Account = new OrmModels.OrmAccount(store, realTime); this.ApplicationCredential = new OrmModels.OrmApplicationCredential(store, realTime); diff --git a/tests/ng2web/src/app/shared/sdk/services/core/base.service.ts b/tests/ng2web/src/app/shared/sdk/services/core/base.service.ts index cd466c21..ec058115 100644 --- a/tests/ng2web/src/app/shared/sdk/services/core/base.service.ts +++ b/tests/ng2web/src/app/shared/sdk/services/core/base.service.ts @@ -99,7 +99,7 @@ export abstract class BaseLoopBackApi { if (LoopBackConfig.isHeadersFilteringSet()) { headers.append('filter', JSON.stringify(urlParams.filter)); } else { - filter = `?filter=${ encodeURI(JSON.stringify(urlParams.filter))}`; + filter = `?filter=${ encodeURIComponent(JSON.stringify(urlParams.filter))}`; } delete urlParams.filter; } @@ -119,12 +119,12 @@ export abstract class BaseLoopBackApi { this.searchParams.setJSON(urlParams); let request: Request = new Request( new RequestOptions({ - headers : headers, - method : method, - url : `${url}${filter}`, - search : Object.keys(urlParams).length > 0 - ? this.searchParams.getURLSearchParams() : null, - body : body ? JSON.stringify(body) : undefined + headers : headers, + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 ? this.searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined, + withCredentials: LoopBackConfig.getRequestOptionsCredentials() }) ); return this.http.request(request) diff --git a/tests/react-web/README.md b/tests/react-web/README.md new file mode 100644 index 00000000..4a1326c4 --- /dev/null +++ b/tests/react-web/README.md @@ -0,0 +1,39 @@ +# How to Test React Components Using Jest + +A repository written for a [blog post about testing React with Jest](https://www.sitepoint.com/test-react-components-jest). + +## Requirements + +* [Node.js](http://nodejs.org/) + +## Running locally + +- `git clone` this repo +- `cd testing-react-with-jest` +- `npm install` +- In one tab, run `npm run watch`. This will fire up Webpack and rebuild your app on each change. +- In another tab, run `npm start`. This will fire up a local server that will refresh automatically when the code changes. +- `open http://localhost:8081` to view to the app. + +## Tests + +Run `npm test` to run the tests with Jest. + +Run `npm test -- --watch` to run Jest and have it automatically rerun everytime you change a file. + +## Problems / Questions + +Please feel free to raise an issue if you have any Qs :) + + +## License + +The MIT License (MIT) + +Copyright (c) 2016 SitePoint + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/react-web/__tests__/App.test.js b/tests/react-web/__tests__/App.test.js new file mode 100644 index 00000000..2a7395fe --- /dev/null +++ b/tests/react-web/__tests__/App.test.js @@ -0,0 +1,21 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './../app/App'; +import { RoomApi } from './../app/shared/sdk/services/custom/Room'; + +it('renders without crashing', () => { + setTimeout(()=> { + console.log('.....') + }, 5000); + const div = document.createElement('div'); + ReactDOM.render(, div); +}); + +it('service RoomApi should be singleton', () => { + const roomApi = new RoomApi(); + const roomApi2 = new RoomApi(); + roomApi2.test = 'Hello World'; + const result = roomApi.test; + expect(result).toBe('Hello World'); + // Todo assert if property test is equal to HelloWorld +}) \ No newline at end of file diff --git a/tests/react-web/__tests__/room-service.test.js b/tests/react-web/__tests__/room-service.test.js new file mode 100644 index 00000000..13736d29 --- /dev/null +++ b/tests/react-web/__tests__/room-service.test.js @@ -0,0 +1,222 @@ +import { Room, Category, Message, FireLoopRef } from './../app/shared/sdk/models'; +import { RoomApi, CategoryApi, MessageApi, RealTime } from './../app/shared/sdk/services'; +let roomApi; +describe('Service Service', () => { + beforeEach(() => { + roomApi = new RoomApi(); + }); + + it('should contain persisted model methods', () => { + expect(roomApi).toBeTruthy(); + expect(roomApi.create).toBeTruthy(); + expect(roomApi.exists).toBeTruthy(); + expect(roomApi.updateAll).toBeTruthy(); + expect(roomApi.updateAttributes).toBeTruthy(); + expect(roomApi.find).toBeTruthy(); + expect(roomApi.findById).toBeTruthy(); + expect(roomApi.findOne).toBeTruthy(); + }) + }); + + it('should create a new room instance', async() => { + let room = new Room(); + room.name = Date.now().toString(); + await roomApi.create(room) + .subscribe((instance) => expect(instance.id).toBeTruthy()); + }); + + it('should find room instance by id', async() => { + let room = new Room(); + room.name = Date.now().toString(); + await roomApi.create(room) + .subscribe((createdRoom) => { + expect(createdRoom.id).toBeTruthy(); + console.log('CREATED:', createdRoom); + roomApi.findById(createdRoom.id) + .subscribe((foundRoom) => { + console.log('FOUND:', foundRoom); + expect(foundRoom.id).toBe(createdRoom.id); + }); + }); + + it('should update room attributes', async () => { + let room = new Room(); + room.name = Date.now().toString(); + await roomApi.create(room) + .subscribe((createdRoom) => { + expect(createdRoom.id).toBeTruthy(); + roomApi.updateAttributes(createdRoom.id, { name: 'updated!!!'}) + .subscribe((updatedRoom) => { + expect(updatedRoom.id).toBe(createdRoom.id); + expect(updatedRoom.name).toBe('updated!!!'); + }); + }); + }); + + it('should patch room attributes', async () => { + let room = new Room(); + room.name = Date.now().toString(); + await roomApi.create(room) + .subscribe((createdRoom) => { + expect(createdRoom.id).toBeTruthy(); + roomApi.updateAttributes(createdRoom.id, { name: 'patched!!!'}) + .subscribe((patchedRoom) => { + expect(patchedRoom.id).toBe(createdRoom.id); + expect(patchedRoom.name).toBe('patched!!!'); + }); + }); + }); + + it('should create a room message', async() => { + let room = new Room(); + room.name = Date.now().toString(); + await roomApi.create(room).subscribe((instance) => + roomApi.createMessages(instance.id, { + text: 'HelloRoom' + }).subscribe(message => { + expect(message.id).toBeTruthy(); + expect(message.roomId).toBe(instance.id); + }) + ); + }); + + it('should create and find a room message using loopback query filter (Interface Test)', async () => { + let room = new Room(); + room.name = Date.now().toString(); + let message = { text: 'Hello Room with Query' }; + await roomApi.create(room) + .subscribe((instance) => roomApi.createMessages(instance.id, message) + .subscribe(messageInstance => roomApi.getMessages(instance.id, { where }) + .subscribe(messages => { + expect(messages.length).toBe(1); + let msg = messages.pop(); + expect(msg.text).toBe(messageInstance.text); + }))); + }); + + it('should property and filter params', async() => { + let filter = { where: 'Yo' }; + await roomApi.getPropertyValues('newfilter', filter) + .subscribe((result) => { + expect(filter.where).toBe(result.newfilter.where); + }); + }); + + it('should fetch greetings from route params', async() => { + let params = ['Hi', 'My Name Is', 'What']; + await roomApi.greetRoute(params[0], params[1], params[2]) + .subscribe((result) => { + expect(result.greeting).toBe(params.join(':')); + }); + }); + + it('should fetch greetings from get method', async() => { + let params = ['Hi', 'My Name Is', 'Who']; + await roomApi.greetGet(params[0], params[1], params[2]) + .subscribe((result) => { + expect(result.greeting).toBe(params.join(':')); + }); + }); + + it('should fetch greetings from post method', async() => { + let params = ['Hi', 'My Name Is', 'Slim Shady!!']; + await roomApi.greetPost(params[0], params[1], params[2]) + .subscribe((result) => { + expect(result.greeting).toBe(params.join(':')); + }); + }); + + it('should find by mock room to test custom remote method', async() => { + let room = new Room({ id: 42, name: 'my awesome room' }); + await roomApi.findByRoom(room) + .subscribe((instance) => { + expect(room.id).toBe(instance.id); + }); + }); + + it('should fetch filter as object from single-param post method', async() => { + let param = { child: 'filtered' }; + await roomApi.singleParamPost(param).subscribe((result) => { + expect(result.param).toBe(undefined); + expect(result.child).toBe(param.child); + }); + }); + + it('should create and link rooms with categories', async() => { + let category = new Category(); + let room = new Room(); + room.name = Date.now().toString(); + category.name = Date.now().toString(); + + await roomApi.create(room) + .subscribe((roomInstance) => categoryApi.create(category) + .subscribe((categoryInstance) => categoryApi.linkRooms(categoryInstance.id, roomInstance.id) + .subscribe((result) => { + expect(result.id).toBeTruthy(); + }))); + }); + + it('should include multiple layers', async() => { + let room = new Room({ name: Date.now().toString() }); + let message = new Message({ text: 'Hello Room' }); + let reply = new Message({ text: 'Hello Reply' }); + await roomApi.create(room) + .subscribe((instance) => roomApi.createMessages(instance.id, message) + .subscribe((messageInstance) => messageApi.createReplies(messageInstance.id, reply) + .subscribe((replyInstance) => messageApi.createLikes(replyInstance.id, { set: true }) + .subscribe((likeInstance) => roomApi.find({ + where: { id: instance.id }, + include: { + relation: 'messages', + scope: { + include: { + relation: 'replies', + scope: { + include: { + relation: 'likes' + } + } + } + } + } + }).subscribe((result) => { + expect(result.length).toBe(1); + expect(result[0].messages.length).toBe(1); + expect(result[0].messages[0].replies.length).toBe(1); + expect(result[0].messages[0].replies[0].likes.length).toBe(1); + }))))); + }); + + /** + * This test is to validate that contexts support is working + * i modify the name of the room appending the host to the name if it works + * if it doesn't work i set room.id = -1 and the name to blank + */ + + it('should find by mock room to test custom remote method with context enabled', async() => { + let room = new Room({ id: 42, name: 'my awesome room' }); + return roomApi.findByRoomContext(room).subscribe( (instance) => { + expect(room.id).toBe(Number.parseInt(instance.id)); + // I append the host onto the instance name so it shouldn't match now + expect(room.name).not.toBe(instance.name); + }); + }); + + it('should return correct response if the room does not exist', async() => { + await roomApi.exists(42) + .subscribe((result) => { + expect(result.exists).toBe(false); + }); + }); + + it('should return correct response if the room does not exist', async() => { + let room = new Room(); + room.name = Date.now().toString(); + return roomApi + .create(room) + .switchMap((instance) => roomApi.exists(instance.id)) + .subscribe((result) => { + expect(result.exists).toBe(true); + }); + }); +}); diff --git a/tests/react-web/__tests__/storage-service.test.js b/tests/react-web/__tests__/storage-service.test.js new file mode 100644 index 00000000..f4d028f7 --- /dev/null +++ b/tests/react-web/__tests__/storage-service.test.js @@ -0,0 +1,48 @@ +import { StorageApi, CategoryApi, MessageApi } from './../app/shared/sdk/services'; +let storageApi; +let categoryApi; +let messageApi; +describe('Service: Storage Service', () => { + beforeEach(() => { + storageApi = new StorageApi(); + categoryApi = new CategoryApi(); + messageApi = new MessageApi(); + }); + + it('should contain storage model methods', () => { + expect(storageApi).toBeTruthy(); + expect(storageApi.createContainer).toBeTruthy(); + expect(storageApi.getContainer).toBeTruthy(); + expect(storageApi.getContainers).toBeTruthy(); + expect(storageApi.destroyContainer).toBeTruthy(); + expect(storageApi.download).toBeTruthy(); + expect(storageApi.getFiles).toBeTruthy(); + expect(storageApi.getFile).toBeTruthy(); + expect(storageApi.removeFile).toBeTruthy(); + expect(storageApi.upload).toBeTruthy(); + }); + + it('should create a new container instance', async () => { + let container = Date.now().toString(); + await storageApi.create({ name: container }) + .subscribe((instance) => { + expect(instance.name).toBeTruthy(); + expect(instance.name).toBe(container); + }); + } + ); + + it('should get a container instance', async () => { + let container = Date.now().toString(); + await storageApi.create({ name: container }) + .subscribe((instance) => { + expect(instance.name).toBeTruthy(); + expect(instance.name).toBe(container); + storageApi.getContainer(container).subscribe((gotInstance) => { + expect(gotInstance.name).toBeTruthy(); + expect(gotInstance.name).toBe(container); + expect(gotInstance.name).toBe(instance.name); + }); + }); + }) +}); diff --git a/tests/react-web/__tests__/user-service.test.js b/tests/react-web/__tests__/user-service.test.js new file mode 100644 index 00000000..d9391200 --- /dev/null +++ b/tests/react-web/__tests__/user-service.test.js @@ -0,0 +1,80 @@ +import { LoopBackConfig } from './../app/shared/sdk'; +import { User, AccessToken } from './../app/shared/sdk/models'; +import { UserApi } from './../app/shared/sdk/services'; + + +let Helpers = { + create : (userApi) => { + let user = new User(); + user.email = Date.now() + '@test.com'; + user.password = 'test'; + return userApi.create(user); + } +} +let userApi; + +describe('Service: User Service', () => { + beforeEach(() => { + userApi = new UserApi; + }); + + it('should contain authentication methods', () => { + expect(userApi).toBeTruthy(); + expect(userApi.login).toBeTruthy(); + expect(userApi.logout).toBeTruthy(); + expect(userApi.getAccessTokens).toBeTruthy(); + expect(userApi.getCurrent).toBeTruthy(); + expect(userApi.getCurrentId).toBeTruthy(); + }); + + it('should create a new instance', async () => { + await Helpers.create(userApi).subscribe( + (instance) => expect(instance.id).toBeTruthy() + ); + }); + + it('should login the user', async () => { + await Helpers.create(userApi) + .subscribe((instance) => userApi.login({ + email: instance.email, + password: 'test' + }) + .subscribe((token) => { + expect(token.id).toBeTruthy(); + expect(token.userId).toBe(instance.id); + })); + }); + + it('should logout the user',async () => { + await Helpers.create(userApi) + .subscribe((instance) => userApi.login({ + email: instance.email, + password: 'test' + }, true) + .subscribe((token) => { + expect(token.id).toBeTruthy(); + expect(token.userId).toBe(instance.id); + userApi.logout().subscribe((res) => { + expect(res).toBeTruthy(); + }); + })); + }); + + it('should fail login the user', async () => { + await userApi.login({ email: 'not@existing.com', password: 'duh' }) + .subscribe((res) => { }, err => expect(err.statusCode).toEqual(401)); + }); + + it('should get current user', async () => { + await Helpers.create(userApi) + .subscribe((instance) => userApi.login({ + email: instance.email, + password: 'test' + }, true) + .subscribe((token) => + userApi.getCurrent().subscribe((current) => { + expect(current.id).toBe(instance.id); + })) + ); + }); +}); diff --git a/tests/react-web/app/App.js b/tests/react-web/app/App.js new file mode 100644 index 00000000..1a16c3e3 --- /dev/null +++ b/tests/react-web/app/App.js @@ -0,0 +1,27 @@ +import React from 'react'; +import SDK, { Component } from './shared/sdk/'; + +class App extends Component { + constructor() { + super({services: ['RoomApi']}); + } + componentDidMount() { + this.RoomApi.find().subscribe(data => { + console.log(data); + }) + } + render() { + return ( +
+
+

Welcome to React

+
+

+ To get started, edit src/App.js and save to reload. +

+
+ ); + } +} + +export default App; diff --git a/tests/react-web/app/index.js b/tests/react-web/app/index.js new file mode 100644 index 00000000..92bc38c6 --- /dev/null +++ b/tests/react-web/app/index.js @@ -0,0 +1,8 @@ +import React from 'react'; +import { render } from 'react-dom'; +import App from './App'; + +render( + , + document.getElementById('app') +); diff --git a/tests/react-web/app/shared/sdk/index.js b/tests/react-web/app/shared/sdk/index.js new file mode 100644 index 00000000..468d9bfd --- /dev/null +++ b/tests/react-web/app/shared/sdk/index.js @@ -0,0 +1,62 @@ + +/** +* @module SDKModule +* @author Jonathan Casarrubias +* @license MIT 2016 Jonathan Casarrubias +* @version 2.1.0 +* @description +* The SDKModule is a generated Software Development Kit automatically built by +* the LoopBack SDK Builder open source module. +* +* The SDKModule provides Angular 2 >= RC.5 support, which means that NgModules +* can import this Software Development Kit as follows: +* +* +* APP Route Module Context +* ============================================================================ +* import { NgModule } from '@angular/core'; +* import { BrowserModule } from '@angular/platform-browser'; +* // App Root +* import { AppComponent } from './app.component'; +* // Feature Modules +* import { SDK[Browser|Node|Native]Module } from './shared/sdk/sdk.module'; +* // Import Routing +* import { routing } from './app.routing'; +* @NgModule({ +* imports: [ +* BrowserModule, +* routing, +* SDK[Browser|Node|Native]Module.forRoot() +* ], +* declarations: [ AppComponent ], +* bootstrap: [ AppComponent ] +* }) +* export class AppModule { } +* +**/ + +import React, { Component as ReactComponent } from 'react'; +import * as Services from './services'; + +export class Component extends ReactComponent { + models = {}; + constructor(config) { + super(); + config.services.forEach((service) => { + if ( typeof this.services === 'object') this.services = {}; + this[service] = new Services[service](); + }); + } +} + + +/** +* Have Fun!!! +* - Jon +**/ +export * from './models/index'; +export * from './services/index'; +export * from './lb.config'; +export * from './storage/storage.swaps'; +export { CookieBrowser } from './storage/cookie.browser'; +export { StorageBrowser } from './storage/storage.browser'; diff --git a/tests/react-web/app/shared/sdk/lb.config.js b/tests/react-web/app/shared/sdk/lb.config.js new file mode 100644 index 00000000..9cb09bae --- /dev/null +++ b/tests/react-web/app/shared/sdk/lb.config.js @@ -0,0 +1,84 @@ +/** +* @module LoopBackConfig +* @description +* +* The LoopBackConfig module help developers to externally +* configure the base url and api version for loopback.io +* +* Example +* +* import { LoopBackConfig } from './sdk'; +* +* @Component() // No metadata needed for this module +* +* export class MyApp { +* constructor() { +* LoopBackConfig.setBaseURL('http://localhost:3000'); +* LoopBackConfig.setApiVersion('api'); +* } +* } +**/ +export class LoopBackConfig { + static path = '//0.0.0.0:3000'; + static version = 'api'; + static authPrefix = ''; + static debug = true; + static filterOn = 'headers'; + static secure = false; + + static setApiVersion(version = 'api') { + LoopBackConfig.version = version; + } + + static getApiVersion() { + return LoopBackConfig.version; + } + + static setBaseURL(url = '/') { + LoopBackConfig.path = url; + } + + static getPath() { + return LoopBackConfig.path; + } + + static setAuthPrefix(authPrefix = '') { + LoopBackConfig.authPrefix = authPrefix; + } + + static getAuthPrefix() { + return LoopBackConfig.authPrefix; + } + + static setDebugMode(isEnabled) { + LoopBackConfig.debug = isEnabled; + } + + static debuggable() { + return LoopBackConfig.debug; + } + + static filterOnUrl() { + LoopBackConfig.filterOn = 'url'; + } + + static filterOnHeaders() { + LoopBackConfig.filterOn = 'headers'; + } + + static isHeadersFilteringSet() { + return (LoopBackConfig.filterOn === 'headers'); + } + + static setSecureWebSockets() { + LoopBackConfig.secure = true; + } + + static unsetSecureWebSockets() { + LoopBackConfig.secure = false; + } + + static isSecureWebSocketsSet() { + return LoopBackConfig.secure; + } +} diff --git a/tests/react-web/app/shared/sdk/models/Account.js b/tests/react-web/app/shared/sdk/models/Account.js new file mode 100644 index 00000000..38d3a22e --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Account.js @@ -0,0 +1,103 @@ + +import { + Room +} from '../index'; + + +export class Account { + "realm"; + "username"; + "email"; + "emailVerified"; + "id"; + "createdAt"; + "updatedAt"; + "password"; + accessTokens; + rooms; + administrations; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Account`. + */ + static getModelName() { + return "Account"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Account for dynamic purposes. + **/ + static factory(data) { + return new Account(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Account', + plural: 'accounts', + path: 'accounts', + properties: { + "realm": { + name: 'realm', + type: 'string' + }, + "username": { + name: 'username', + type: 'string' + }, + "email": { + name: 'email', + type: 'string' + }, + "emailVerified": { + name: 'emailVerified', + type: 'boolean' + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + "password": { + name: 'password', + type: 'string' + }, + }, + relations: { + accessTokens: { + name: 'accessTokens', + type: 'any[]', + model: '' + }, + rooms: { + name: 'rooms', + type: 'Room[]', + model: 'Room' + }, + administrations: { + name: 'administrations', + type: 'Room[]', + model: 'Room' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/ApplicationCredential.js b/tests/react-web/app/shared/sdk/models/ApplicationCredential.js new file mode 100644 index 00000000..6719581a --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/ApplicationCredential.js @@ -0,0 +1,90 @@ + + + +export class ApplicationCredential { + "provider"; + "authScheme"; + "credentials"; + "created"; + "modified"; + "userId"; + "id"; + "createdAt"; + "updatedAt"; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `ApplicationCredential`. + */ + static getModelName() { + return "ApplicationCredential"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of ApplicationCredential for dynamic purposes. + **/ + static factory(data) { + return new ApplicationCredential(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'ApplicationCredential', + plural: 'application-credentials', + path: 'application-credentials', + properties: { + "provider": { + name: 'provider', + type: 'string', + default: 'authScheme' + }, + "authScheme": { + name: 'authScheme', + type: 'string', + default: '' + }, + "credentials": { + name: 'credentials', + type: 'string', + default: '' + }, + "created": { + name: 'created', + type: 'Date' + }, + "modified": { + name: 'modified', + type: 'Date' + }, + "userId": { + name: 'userId', + type: 'any' + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/BaseModels.js b/tests/react-web/app/shared/sdk/models/BaseModels.js new file mode 100644 index 00000000..391db6fe --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/BaseModels.js @@ -0,0 +1,86 @@ + + +export class AccessToken { + "id"; + "ttl"; + "scopes"; + "created"; + "userId"; + "user"; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `AccessToken`. + */ + static getModelName() { + return "AccessToken"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of AccessToken for dynamic purposes. + **/ + static factory(data) { + return new AccessToken(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'AccessToken', + plural: 'AccessTokens', + properties: { + "id": { + name: 'id', + type: 'string' + }, + "ttl": { + name: 'ttl', + type: 'number', + default: 1209600 + }, + "scopes": { + name: 'scopes', + type: '["string"]' + }, + "created": { + name: 'created', + type: 'Date' + }, + "userId": { + name: 'userId', + type: 'string' + }, + }, + relations: { + user: { + name: 'user', + type: 'User', + model: 'User' + }, + } + } + } +} + +export class SDKToken { + id = null; + ttl = null; + scopes = null; + created = null; + userId = null; + user = null; + rememberMe = null; + constructor(data) { + Object.assign(this, data); + } +} + diff --git a/tests/react-web/app/shared/sdk/models/Category.js b/tests/react-web/app/shared/sdk/models/Category.js new file mode 100644 index 00000000..54d8b386 --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Category.js @@ -0,0 +1,72 @@ + +import { + Room +} from '../index'; + + +export class Category { + "name"; + "id"; + "createdAt"; + "updatedAt"; + rooms; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Category`. + */ + static getModelName() { + return "Category"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Category for dynamic purposes. + **/ + static factory(data) { + return new Category(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Category', + plural: 'categories', + path: 'categories', + properties: { + "name": { + name: 'name', + type: 'string', + default: 'test' + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + rooms: { + name: 'rooms', + type: 'Room[]', + model: 'Room' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/Core.js b/tests/react-web/app/shared/sdk/models/Core.js new file mode 100644 index 00000000..1fbd6514 --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Core.js @@ -0,0 +1,57 @@ + + + +export class Core { + "id"; + "createdAt"; + "updatedAt"; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Core`. + */ + static getModelName() { + return "Core"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Core for dynamic purposes. + **/ + static factory(data) { + return new Core(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Core', + plural: 'cores', + path: 'cores', + properties: { + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/Like.js b/tests/react-web/app/shared/sdk/models/Like.js new file mode 100644 index 00000000..f5266f1b --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Like.js @@ -0,0 +1,89 @@ + +import { + Message, + Room +} from '../index'; + + +export class Like { + "set"; + "id"; + "createdAt"; + "updatedAt"; + "messageId"; + "roomId"; + message; + room; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Like`. + */ + static getModelName() { + return "Like"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Like for dynamic purposes. + **/ + static factory(data) { + return new Like(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Like', + plural: 'likes', + path: 'likes', + properties: { + "set": { + name: 'set', + type: 'boolean', + default: true + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + "messageId": { + name: 'messageId', + type: 'any' + }, + "roomId": { + name: 'roomId', + type: 'any' + }, + }, + relations: { + message: { + name: 'message', + type: 'Message', + model: 'Message' + }, + room: { + name: 'room', + type: 'Room', + model: 'Room' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/Message.js b/tests/react-web/app/shared/sdk/models/Message.js new file mode 100644 index 00000000..1f5c7bea --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Message.js @@ -0,0 +1,101 @@ + +import { + Like, + Room +} from '../index'; + + +export class Message { + "text"; + "id"; + "parentId"; + "createdAt"; + "updatedAt"; + "roomId"; + likes; + replies; + parent; + room; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Message`. + */ + static getModelName() { + return "Message"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Message for dynamic purposes. + **/ + static factory(data) { + return new Message(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Message', + plural: 'messages', + path: 'messages', + properties: { + "text": { + name: 'text', + type: 'string', + default: '' + }, + "id": { + name: 'id', + type: 'any' + }, + "parentId": { + name: 'parentId', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + "roomId": { + name: 'roomId', + type: 'any' + }, + }, + relations: { + likes: { + name: 'likes', + type: 'Like[]', + model: 'Like' + }, + replies: { + name: 'replies', + type: 'Message[]', + model: 'Message' + }, + parent: { + name: 'parent', + type: 'Message', + model: 'Message' + }, + room: { + name: 'room', + type: 'Room', + model: 'Room' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/Room.js b/tests/react-web/app/shared/sdk/models/Room.js new file mode 100644 index 00000000..2ba438cc --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Room.js @@ -0,0 +1,99 @@ + +import { + Message, + Like, + Category, + Account +} from '../index'; + + +export class Room { + "name"; + "id"; + "createdAt"; + "updatedAt"; + messages; + likes; + categories; + accounts; + admins; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Room`. + */ + static getModelName() { + return "Room"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Room for dynamic purposes. + **/ + static factory(data) { + return new Room(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Room', + plural: 'rooms', + path: 'rooms', + properties: { + "name": { + name: 'name', + type: 'string', + default: '' + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + messages: { + name: 'messages', + type: 'Message[]', + model: 'Message' + }, + likes: { + name: 'likes', + type: 'Like[]', + model: 'Like' + }, + categories: { + name: 'categories', + type: 'Category[]', + model: 'Category' + }, + accounts: { + name: 'accounts', + type: 'Account[]', + model: 'Account' + }, + admins: { + name: 'admins', + type: 'Account[]', + model: 'Account' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/RoomAccount.js b/tests/react-web/app/shared/sdk/models/RoomAccount.js new file mode 100644 index 00000000..3b46e65b --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/RoomAccount.js @@ -0,0 +1,83 @@ + +import { + Account, + Room +} from '../index'; + + +export class RoomAccount { + "id"; + "accountId"; + "roomId"; + "createdAt"; + "updatedAt"; + account; + room; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `RoomAccount`. + */ + static getModelName() { + return "RoomAccount"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of RoomAccount for dynamic purposes. + **/ + static factory(data) { + return new RoomAccount(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'RoomAccount', + plural: 'room-accounts', + path: 'room-accounts', + properties: { + "id": { + name: 'id', + type: 'any' + }, + "accountId": { + name: 'accountId', + type: 'any' + }, + "roomId": { + name: 'roomId', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + account: { + name: 'account', + type: 'Account', + model: 'Account' + }, + room: { + name: 'room', + type: 'Room', + model: 'Room' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/RoomAdmin.js b/tests/react-web/app/shared/sdk/models/RoomAdmin.js new file mode 100644 index 00000000..d8f4ae6a --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/RoomAdmin.js @@ -0,0 +1,83 @@ + +import { + Account, + Room +} from '../index'; + + +export class RoomAdmin { + "id"; + "adminId"; + "administrationId"; + "createdAt"; + "updatedAt"; + account; + room; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `RoomAdmin`. + */ + static getModelName() { + return "RoomAdmin"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of RoomAdmin for dynamic purposes. + **/ + static factory(data) { + return new RoomAdmin(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'RoomAdmin', + plural: 'room-admins', + path: 'room-admins', + properties: { + "id": { + name: 'id', + type: 'any' + }, + "adminId": { + name: 'adminId', + type: 'any' + }, + "administrationId": { + name: 'administrationId', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + account: { + name: 'account', + type: 'Account', + model: 'Account' + }, + room: { + name: 'room', + type: 'Room', + model: 'Room' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/Storage.js b/tests/react-web/app/shared/sdk/models/Storage.js new file mode 100644 index 00000000..b6bbf5e8 --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/Storage.js @@ -0,0 +1,57 @@ + + + +export class Storage { + "id"; + "createdAt"; + "updatedAt"; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `Storage`. + */ + static getModelName() { + return "Storage"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of Storage for dynamic purposes. + **/ + static factory(data) { + return new Storage(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'Storage', + plural: 'storages', + path: 'storages', + properties: { + "id": { + name: 'id', + type: 'number' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/User.js b/tests/react-web/app/shared/sdk/models/User.js new file mode 100644 index 00000000..5a87d831 --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/User.js @@ -0,0 +1,78 @@ + + + +export class User { + "realm"; + "username"; + "email"; + "emailVerified"; + "id"; + "password"; + accessTokens; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `User`. + */ + static getModelName() { + return "User"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of User for dynamic purposes. + **/ + static factory(data) { + return new User(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'User', + plural: 'Users', + path: 'Users', + properties: { + "realm": { + name: 'realm', + type: 'string' + }, + "username": { + name: 'username', + type: 'string' + }, + "email": { + name: 'email', + type: 'string' + }, + "emailVerified": { + name: 'emailVerified', + type: 'boolean' + }, + "id": { + name: 'id', + type: 'any' + }, + "password": { + name: 'password', + type: 'string' + }, + }, + relations: { + accessTokens: { + name: 'accessTokens', + type: 'any[]', + model: '' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/UserCredential.js b/tests/react-web/app/shared/sdk/models/UserCredential.js new file mode 100644 index 00000000..2f09998c --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/UserCredential.js @@ -0,0 +1,103 @@ + + + +export class UserCredential { + "provider"; + "authScheme"; + "externalId"; + "profile"; + "credentials"; + "created"; + "modified"; + "userId"; + "id"; + "createdAt"; + "updatedAt"; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `UserCredential`. + */ + static getModelName() { + return "UserCredential"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of UserCredential for dynamic purposes. + **/ + static factory(data) { + return new UserCredential(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'UserCredential', + plural: 'user-credentials', + path: 'user-credentials', + properties: { + "provider": { + name: 'provider', + type: 'string', + default: 'authScheme' + }, + "authScheme": { + name: 'authScheme', + type: 'string', + default: '' + }, + "externalId": { + name: 'externalId', + type: 'string', + default: '' + }, + "profile": { + name: 'profile', + type: 'any', + default: null + }, + "credentials": { + name: 'credentials', + type: 'string', + default: '' + }, + "created": { + name: 'created', + type: 'Date' + }, + "modified": { + name: 'modified', + type: 'Date', + default: new Date(0) + }, + "userId": { + name: 'userId', + type: 'any' + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/UserIdentity.js b/tests/react-web/app/shared/sdk/models/UserIdentity.js new file mode 100644 index 00000000..80169029 --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/UserIdentity.js @@ -0,0 +1,111 @@ + +import { + User +} from '../index'; + + +export class UserIdentity { + "provider"; + "authScheme"; + "externalId"; + "profile"; + "credentials"; + "created"; + "modified"; + "userId"; + "id"; + "createdAt"; + "updatedAt"; + user; + constructor(data) { + Object.assign(this, data); + } + /** + * The name of the model represented by this $resource, + * i.e. `UserIdentity`. + */ + static getModelName() { + return "UserIdentity"; + } + /** + * @method factory + * @author Jonathan Casarrubias + * @license MIT + * This method creates an instance of UserIdentity for dynamic purposes. + **/ + static factory(data) { + return new UserIdentity(data); + } + /** + * @method getModelDefinition + * @author Julien Ledun + * @license MIT + * This method returns an object that represents some of the model + * definitions. + **/ + static getModelDefinition() { + return { + name: 'UserIdentity', + plural: 'user-identities', + path: 'user-identities', + properties: { + "provider": { + name: 'provider', + type: 'string', + default: 'authScheme' + }, + "authScheme": { + name: 'authScheme', + type: 'string', + default: '' + }, + "externalId": { + name: 'externalId', + type: 'string', + default: '' + }, + "profile": { + name: 'profile', + type: 'any', + default: null + }, + "credentials": { + name: 'credentials', + type: 'string', + default: '' + }, + "created": { + name: 'created', + type: 'Date' + }, + "modified": { + name: 'modified', + type: 'Date' + }, + "userId": { + name: 'userId', + type: 'any' + }, + "id": { + name: 'id', + type: 'any' + }, + "createdAt": { + name: 'createdAt', + type: 'Date' + }, + "updatedAt": { + name: 'updatedAt', + type: 'Date' + }, + }, + relations: { + user: { + name: 'user', + type: 'User', + model: 'User' + }, + } + } + } +} diff --git a/tests/react-web/app/shared/sdk/models/index.js b/tests/react-web/app/shared/sdk/models/index.js new file mode 100644 index 00000000..b6f760f0 --- /dev/null +++ b/tests/react-web/app/shared/sdk/models/index.js @@ -0,0 +1,16 @@ +/* tslint:disable */ +export * from './User'; +export * from './Account'; +export * from './ApplicationCredential'; +export * from './Category'; +export * from './Core'; +export * from './Like'; +export * from './Message'; +export * from './Room'; +export * from './RoomAccount'; +export * from './RoomAdmin'; +export * from './Storage'; +export * from './UserCredential'; +export * from './UserIdentity'; +export * from './BaseModels'; + diff --git a/tests/react-web/app/shared/sdk/services/core/auth.service.js b/tests/react-web/app/shared/sdk/services/core/auth.service.js new file mode 100644 index 00000000..fd0b276f --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/core/auth.service.js @@ -0,0 +1,167 @@ + + +import { InternalStorage } from '../../storage/storage.swaps'; +import { SDKToken } from '../../models/BaseModels'; +/** +* @author Jonathan Casarrubias +* @module SocketConnection +* @license MIT +* @description +* This module handle socket connections and return singleton instances for each +* connection, it will use the SDK Socket Driver Available currently supporting +* Angular 2 for web, NativeScript 2 and Angular Universal. +**/ + +export class LoopBackAuth { + /** + * @type {SDKToken} + **/ + token = new SDKToken(); + /** + * @type {string} + **/ + prefix = '$LoopBackSDK$'; + /** + * @method constructor + * @param {InternalStorage} storage Internal Storage Driver + * @description + * The constructor will initialize the token loading data from storage + **/ + constructor() { + this.storage = new InternalStorage(); + + this.token.id = this.load('id'); + this.token.user = this.load('user'); + this.token.userId = this.load('userId'); + this.token.created = this.load('created'); + this.token.ttl = this.load('ttl'); + this.token.rememberMe = this.load('rememberMe'); + } + /** + * @method setRememberMe + * @param {boolean} value Flag to remember credentials + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials + **/ + setRememberMe(value) { + this.token.rememberMe = value; + } + /** + * @method setUser + * @param {any} user Any type of user model + * @return {void} + * @description + * This method will update the user information and persist it if the + * rememberMe flag is set. + **/ + setUser(user) { + this.token.user = user; + this.save(); + } + /** + * @method setToken + * @param {SDKToken} token SDKToken or casted AccessToken instance + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials + **/ + setToken(token) { + this.token = Object.assign(this.token, token); + this.save(); + } + /** + * @method getToken + * @return {void} + * @description + * This method will set a flag in order to remember the current credentials. + **/ + getToken() { + return this.token; + } + /** + * @method getAccessTokenId + * @return {string} + * @description + * This method will return the actual token string, not the object instance. + **/ + getAccessTokenId() { + return this.token.id; + } + /** + * @method getCurrentUserId + * @return {any} + * @description + * This method will return the current user id, it can be number or string. + **/ + getCurrentUserId() { + return this.token.userId; + } + /** + * @method getCurrentUserData + * @return {any} + * @description + * This method will return the current user instance. + **/ + getCurrentUserData() { + return (typeof this.token.user === 'string') ? JSON.parse(this.token.user) : this.token.user; + } + /** + * @method save + * @return {boolean} Whether or not the information was saved + * @description + * This method will save in either local storage or cookies the current credentials. + * But only if rememberMe is enabled. + **/ + save() { + if (this.token.rememberMe) { + this.persist('id', this.token.id); + this.persist('user', this.token.user); + this.persist('userId', this.token.userId); + this.persist('created', this.token.created); + this.persist('ttl', this.token.ttl); + this.persist('rememberMe', this.token.rememberMe); + return true; + } else { + return false; + } + }; + /** + * @method load + * @param {string} prop Property name + * @return {any} Any information persisted in storage + * @description + * This method will load either from local storage or cookies the provided property. + **/ + load(prop) { + return this.storage.get(`${this.prefix}${prop}`); + } + /** + * @method clear + * @return {void} + * @description + * This method will clear cookies or the local storage. + **/ + clear() { + Object.keys(this.token).forEach((prop) => this.storage.remove(`${this.prefix}${prop}`)); + this.token = new SDKToken(); + } + /** + * @method persist + * @return {void} + * @description + * This method saves values to storage + **/ + persist(prop, value) { + try { + this.storage.set( + `${this.prefix}${prop}`, + (typeof value === 'object') ? JSON.stringify(value) : value + ); + } + catch (err) { + console.error('Cannot access local/session storage:', err); + } + } + +} diff --git a/tests/react-web/app/shared/sdk/services/core/base.service.js b/tests/react-web/app/shared/sdk/services/core/base.service.js new file mode 100644 index 00000000..bbe38d9a --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/core/base.service.js @@ -0,0 +1,450 @@ +import { JSONSearchParams } from './search.params'; +import { ErrorHandler } from './error.service'; +import { LoopBackAuth } from './auth.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, AccessToken } from '../../models/BaseModels'; +import { SDKModels } from '../custom/SDKModels'; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/map'; + +import axios from 'axios'; +import 'rxjs/add/observable/fromPromise'; + +/** +* @module BaseLoopBackApi +* @author Jonathan Casarrubias <@johncasarrubias> +* @author Nikolay Matiushenkov +* @license MIT +* @description +* Abstract class that will be implemented in every custom service automatically built +* by the sdk builder. +* It provides the core functionallity for every API call, either by HTTP Calls or by +* WebSockets. +**/ + + + let instance = null; + +export class BaseLoopBackApi { + + path; + model; + models; + auth; + + constructor( + + ) { + this.models = new SDKModels(); + this.model = this.models.get(this.getModelName()); + this.auth = new LoopBackAuth(); + if (instance) { + return instance; + } + instance = this; + + + } + /** + * @method request + * @param {string} method Request method (GET, POST, PUT) + * @param {string} url Request url (my-host/my-url/:id) + * @param {any} routeParams Values of url parameters + * @param {any} urlParams Parameters for building url (filter and other) + * @param {any} postBody Request postBody + * @return {Observable} + * @description + * This is a core method, every HTTP Call will be done from here, every API Service will + * extend this class and use this method to get RESTful communication. + **/ + request( + method, + url, + routeParams = {}, + urlParams = {}, + postBody = {}, + pubsub = false, + customHeaders + ) { + // Transpile route variables to the actual request Values + Object.keys(routeParams).forEach((key) => { + url = url.replace(new RegExp(":" + key + "(\/|$)", "g"), routeParams[key] + "$1") + }); + if (pubsub) { + console.info('SDK: PubSub functionality is disabled, generate SDK using -io enabled'); + } else { + // Headers to be sent + + +let headers = { + 'Content-Type': 'application/json' + }; + + // Authenticate request + this.authenticate(url, headers); + // Body fix for built in remote methods using "data", "options" or "credentials + // that are the actual body, Custom remote method properties are different and need + // to be wrapped into a body object + let body; + let postBodyKeys = typeof postBody === 'object' ? Object.keys(postBody) : [] + if (postBodyKeys.length === 1) { + body = postBody[postBodyKeys.shift()]; + } else { + body = postBody; + } + let filter = ''; + // Separate filter object from url params and add to search query + if (urlParams.filter) { + if (LoopBackConfig.isHeadersFilteringSet()) { + + headers.filter = JSON.stringify(urlParams.filter); + + } else { + filter = `?filter=${ encodeURI(JSON.stringify(urlParams.filter))}`; + } + delete urlParams.filter; + } + // Separate where object from url params and add to search query + /** + CODE BELOW WILL GENERATE THE FOLLOWING ISSUES: + - https://github.com/mean-expert-official/loopback-sdk-builder/issues/356 + - https://github.com/mean-expert-official/loopback-sdk-builder/issues/328 + if (urlParams.where) { + headers.append('where', JSON.stringify(urlParams.where)); + delete urlParams.where; + } + **/ + if (typeof customHeaders === 'function') { + headers = customHeaders(headers); + } + + let searchParams = new JSONSearchParams(); + let errorHandler = new ErrorHandler(); + searchParams.setJSON(urlParams); + let request = new axios.request({ + headers , + method : method, + url : `${url}${filter}`, + search : Object.keys(urlParams).length > 0 + ? searchParams.getURLSearchParams() : null, + body : body ? JSON.stringify(body) : undefined + } + ); + return Observable.fromPromise(request) + .map((res) => res.data) + .catch((e) => errorHandler.handleError(e)); + + } + } + /** + * @method authenticate + * @author Jonathan Casarrubias + * @license MIT + * @param {string} url Server URL + * @param {Headers} headers HTTP Headers + * @return {void} + * @description + * This method will try to authenticate using either an access_token or basic http auth + */ + authenticate(url, headers) { + if (this.auth.getAccessTokenId()) { + + headers.Authorization = LoopBackConfig.getAuthPrefix() + this.auth.getAccessTokenId(); + + } + } + /** + * @method create + * @author Jonathan Casarrubias + * @license MIT + * @param {T} data Generic data type + * @return {Observable} + * @description + * Generic create method + */ + create(data, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, null, customHeaders).map((data) => this.model.factory(data)); + } + /** + * @method createMany + * @author Jonathan Casarrubias + * @license MIT + * @param {T[]} data Generic data type array + * @return {Observable} + * @description + * Generic create many method + */ + createMany(data, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((datum) => datum.map((data) => this.model.factory(data))); + } + /** + * @method findById + * @author Jonathan Casarrubias + * @license MIT + * @param {any} data Generic data type + * @return {Observable} + * @description + * Generic findById method + */ + findById(id, filter = {}, customHeaders) { + let _urlParams = {}; + if (filter) _urlParams.filter = filter; + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, _urlParams, undefined, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method find + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic find method + */ + find(filter = {}, customHeaders) { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path + ].join('/'), undefined, { filter }, undefined, null, customHeaders) + .map((datum) => datum.map((data) => this.model.factory(data))); + } + /** + * @method exists + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic exists method + */ + exists(id, customHeaders) { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id/exists' + ].join('/'), { id }, undefined, undefined, null, customHeaders); + } + /** + * @method findOne + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic findOne method + */ + findOne(filter = {}, customHeaders) { + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'findOne' + ].join('/'), undefined, { filter }, undefined, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method updateAll + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic updateAll method + */ + updateAll(where = {}, data, customHeaders) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'update' + ].join('/'), undefined, _urlParams, { data }, null, customHeaders); + } + /** + * @method deleteById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic deleteById method + */ + deleteById(id, customHeaders) { + return this.request('DELETE', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, undefined, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method count + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable<{ count: number }>} + * @description + * Generic count method + */ + count(where = {}, customHeaders) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('GET', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'count' + ].join('/'), undefined, _urlParams, undefined, null, customHeaders); + } + /** + * @method updateAttributes + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic updateAttributes method + */ + updateAttributes(id, data, customHeaders) { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id' + ].join('/'), { id }, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method upsert + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsert method + */ + upsert(data = {}, customHeaders) { + return this.request('PUT', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method upsertPatch + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsert method using patch http method + */ + upsertPatch(data = {}, customHeaders) { + return this.request('PATCH', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method upsertWithWhere + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic upsertWithWhere method + */ + upsertWithWhere(where = {}, data = {}, customHeaders) { + let _urlParams = {}; + if (where) _urlParams.where = where; + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'upsertWithWhere' + ].join('/'), undefined, _urlParams, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method replaceOrCreate + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic replaceOrCreate method + */ + replaceOrCreate(data = {}, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'replaceOrCreate' + ].join('/'), undefined, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method replaceById + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic replaceById method + */ + replaceById(id, data = {}, customHeaders) { + return this.request('POST', [ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + ':id', 'replace' + ].join('/'), { id }, undefined, { data }, null, customHeaders) + .map((data) => this.model.factory(data)); + } + /** + * @method createChangeStream + * @author Jonathan Casarrubias + * @license MIT + * @return {Observable} + * @description + * Generic createChangeStream method + */ + createChangeStream() { + let subject = new Subject(); + if (typeof EventSource !== 'undefined') { + let emit = (msg) => subject.next(JSON.parse(msg.data)); + var source = new EventSource([ + LoopBackConfig.getPath(), + LoopBackConfig.getApiVersion(), + this.model.getModelDefinition().path, + 'change-stream' + ].join('/')); + source.addEventListener('data', emit); + source.onerror = emit; + } else { + console.warn('SDK Builder: EventSource is not supported'); + } + return subject.asObservable(); + } + /** + * @method getModelName + * @author Jonathan Casarrubias + * @license MIT + * @return {string} + * @description + * getModelName method + */ + getModelName() {}; +} diff --git a/tests/react-web/app/shared/sdk/services/core/error.service.js b/tests/react-web/app/shared/sdk/services/core/error.service.js new file mode 100644 index 00000000..6326b350 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/core/error.service.js @@ -0,0 +1,17 @@ + +import { Observable } from 'rxjs/Observable'; +//import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; +import 'rxjs/add/observable/throw'; +/** + * Default error handler + */ + +export class ErrorHandler { + // ErrorObservable when rxjs version < rc.5 + // ErrorObservable when rxjs version = rc.5 + // I'm leaving any for now to avoid breaking apps using both versions + handleError(error) { + return Observable.throw(error.json().error || 'Server error'); + } +} + diff --git a/tests/react-web/app/shared/sdk/services/core/index.js b/tests/react-web/app/shared/sdk/services/core/index.js new file mode 100644 index 00000000..e559e570 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/core/index.js @@ -0,0 +1,6 @@ +/* tslint:disable */ +export * from './auth.service'; +export * from './error.service'; +export * from './search.params'; +export * from './base.service'; + diff --git a/tests/react-web/app/shared/sdk/services/core/search.params.js b/tests/react-web/app/shared/sdk/services/core/search.params.js new file mode 100644 index 00000000..e8dc6742 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/core/search.params.js @@ -0,0 +1,41 @@ + +/** +* @author Jonathan Casarrubias +* @module JSONSearchParams +* @license MIT +* @description +* JSON Parser and Wrapper for the Angular2 URLSearchParams +* This module correctly encodes a json object into a query string and then creates +* an instance of the URLSearchParams component for later use in HTTP Calls +**/ + +export class JSONSearchParams { + + _usp; + + setJSON(obj) { + + this._usp = this._JSON2URL(obj, false); + + } + + getURLSearchParams() { + return this._usp; + } + + _JSON2URL(obj, parent) { + var parts = []; + for (var key in obj) + parts.push(this._parseParam(key, obj[key], parent)); + return parts.join('&'); + } + + _parseParam(key, value, parent) { + let processedKey = parent ? parent + '[' + key + ']' : key; + if (value && ((typeof value) === 'object' || Array.isArray(value))) { + return this._JSON2URL(value, processedKey); + } + return processedKey + '=' + value; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/Account.js b/tests/react-web/app/shared/sdk/services/custom/Account.js new file mode 100644 index 00000000..1354d3ff --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Account.js @@ -0,0 +1,1476 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, SDKToken, AccessToken } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Account } from '../../models/Account'; +import { RoomAccount } from '../../models/RoomAccount'; +import { Room } from '../../models/Room'; +import { RoomAdmin } from '../../models/RoomAdmin'; + + +/** + * Api services for the `Account` model. + */ + +export class AccountApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Find a related item by id for accessTokens. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for accessTokens + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + findByIdAccessTokens(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for accessTokens. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for accessTokens + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdAccessTokens(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for accessTokens. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for accessTokens + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + updateByIdAccessTokens(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for rooms. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + findByIdRooms(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for rooms. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdRooms(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for rooms. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for rooms + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + updateByIdRooms(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Add a related item by id for rooms. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for rooms + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + linkRooms(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Remove the rooms relation to an item by id. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + unlinkRooms(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Check the existence of rooms relation to an item by id. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + existsRooms(id, fk, customHeaders) { + + let _method = "HEAD"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for administrations. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for administrations + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + findByIdAdministrations(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for administrations. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for administrations + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdAdministrations(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for administrations. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for administrations + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + updateByIdAdministrations(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Add a related item by id for administrations. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for administrations + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + linkAdministrations(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Remove the administrations relation to an item by id. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for administrations + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + unlinkAdministrations(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Check the existence of administrations relation to an item by id. + * + * @param {any} id Account id + * + * @param {any} fk Foreign key for administrations + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + existsAdministrations(id, fk, customHeaders) { + + let _method = "HEAD"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries accessTokens of Account. + * + * @param {any} id Account id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + getAccessTokens(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in accessTokens of this model. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + createAccessTokens(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all accessTokens of this model. + * + * @param {any} id Account id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteAccessTokens(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts accessTokens of Account. + * + * @param {any} id Account id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countAccessTokens(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries rooms of Account. + * + * @param {any} id Account id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + getRooms(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in rooms of this model. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + createRooms(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all rooms of this model. + * + * @param {any} id Account id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteRooms(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts rooms of Account. + * + * @param {any} id Account id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countRooms(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries administrations of Account. + * + * @param {any} id Account id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + getAdministrations(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in administrations of this model. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + createAdministrations(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all administrations of this model. + * + * @param {any} id Account id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteAdministrations(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts administrations of Account. + * + * @param {any} id Account id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countAdministrations(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Login a user with username/email and password. + * + * @param {string} include Related objects to include in the response. See the description of return value for more details. + * Default value: `user`. + * + * - `rememberMe` - `boolean` - Whether the authentication credentials + * should be remembered in localStorage across app/browser restarts. + * Default: `true`. + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * The response body contains properties of the AccessToken created on login. + * Depending on the value of `include` parameter, the body may contain additional properties: + * + * - `user` - `U+007BUserU+007D` - Data of the currently logged in user. (`include=user`) + * + * + */ + login(credentials, include, rememberMe = true, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/login"; + let _routeParams = {}; + let _postBody = { + credentials: credentials + }; + let _urlParams = {}; + + + if (typeof include !== 'undefined' && include !== null) _urlParams.include = include; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders) + .map( + (response) => { + response.ttl = parseInt(response.ttl); + response.rememberMe = rememberMe; + this.auth.setToken(response); + return response; + } + ); + return result; + + } + + /** + * Logout a user with access token. + * + * @param {object} data Request data. + * + * This method does not accept any data. Supply an empty object. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + logout(customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/logout"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + _urlParams.access_token = this.auth.getAccessTokenId(); + this.auth.clear(); + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Trigger user's identity verification with configured verifyOptions + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method does not accept any data. Supply an empty object. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + verify(id, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/verify"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Confirm a user registration with identity verification token. + * + * @param {string} uid + * + * @param {string} token + * + * @param {string} redirect + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + confirm(uid, token, redirect, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/confirm"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof uid !== 'undefined' && uid !== null) _urlParams.uid = uid; + if (typeof token !== 'undefined' && token !== null) _urlParams.token = token; + if (typeof redirect !== 'undefined' && redirect !== null) _urlParams.redirect = redirect; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Reset password for a user with email. + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + resetPassword(options, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/reset"; + let _routeParams = {}; + let _postBody = { + options: options + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Change a user's password. + * + * @param {object} data Request data. + * + * - `oldPassword` – `{string}` - + * + * - `newPassword` – `{string}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + changePassword(oldPassword, newPassword, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/change-password"; + let _routeParams = {}; + let _postBody = { + data: { + oldPassword: oldPassword, + newPassword: newPassword + } + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Reset user's password via a password-reset token. + * + * @param {object} data Request data. + * + * - `newPassword` – `{string}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + setPassword(newPassword, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/reset-password"; + let _routeParams = {}; + let _postBody = { + data: { + newPassword: newPassword + } + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Account registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in accessTokens of this model. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + createManyAccessTokens(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in rooms of this model. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + createManyRooms(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in administrations of this model. + * + * @param {any} id Account id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Account` object.) + * + */ + createManyAdministrations(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/accounts/:id/administrations"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + /** + * @ngdoc method + * @name sdk.Account#getCurrent + * @methodOf sdk.Account + * + * @description + * + * Get data of the currently logged user. Fail with HTTP result 401 + * when there is no user logged in. + * + * @returns object An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + */ + getCurrent(filter = {}) { + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + "/accounts" + "/:id"; + let id = this.auth.getCurrentUserId(); + if (id == null) + id = '__anonymous__'; + let _routeParams = { id: id }; + let _urlParams = {}; + let _postBody = {}; + if (filter) _urlParams.filter = filter; + return this.request(_method, _url, _routeParams, _urlParams, _postBody); + } + /** + * Get data of the currently logged user that was returned by the last + * call to {@link sdk.Account#login} or + * {@link sdk.Account#getCurrent}. Return null when there + * is no user logged in or the data of the current user were not fetched + * yet. + * + * @returns object An Account instance. + */ + getCachedCurrent() { + return this.auth.getCurrentUserData(); + } + /** + * Get data of the currently logged access tokern that was returned by the last + * call to {@link sdk.Account#login} + * + * @returns object An AccessToken instance. + */ + getCurrentToken() { + return this.auth.getToken(); + } + /** + * @name sdk.Account#isAuthenticated + * + * @returns {boolean} True if the current user is authenticated (logged in). + */ + isAuthenticated() { + return !(this.getCurrentId() === '' || this.getCurrentId() == null || this.getCurrentId() == 'null'); + } + + /** + * @name sdk.Account#getCurrentId + * + * @returns object Id of the currently logged-in user or null. + */ + getCurrentId() { + return this.auth.getCurrentUserId(); + } + + /** + * The name of the model represented by this $resource, + * i.e. `Account`. + */ + getModelName() { + return "Account"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/ApplicationCredential.js b/tests/react-web/app/shared/sdk/services/custom/ApplicationCredential.js new file mode 100644 index 00000000..56e32445 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/ApplicationCredential.js @@ -0,0 +1,170 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { ApplicationCredential } from '../../models/ApplicationCredential'; + + +/** + * Api services for the `ApplicationCredential` model. + */ + +export class ApplicationCredentialApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `ApplicationCredential` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/application-credentials"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id ApplicationCredential id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `ApplicationCredential` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/application-credentials/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/application-credentials/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for ApplicationCredential registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `ApplicationCredential` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/application-credentials/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `ApplicationCredential`. + */ + getModelName() { + return "ApplicationCredential"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/Category.js b/tests/react-web/app/shared/sdk/services/custom/Category.js new file mode 100644 index 00000000..c729d6d7 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Category.js @@ -0,0 +1,539 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Category } from '../../models/Category'; +import { Room } from '../../models/Room'; + + +/** + * Api services for the `Category` model. + */ + +export class CategoryApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Find a related item by id for rooms. + * + * @param {any} id Category id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + findByIdRooms(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for rooms. + * + * @param {any} id Category id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdRooms(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for rooms. + * + * @param {any} id Category id + * + * @param {any} fk Foreign key for rooms + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + updateByIdRooms(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Add a related item by id for rooms. + * + * @param {any} id Category id + * + * @param {any} fk Foreign key for rooms + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + linkRooms(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Remove the rooms relation to an item by id. + * + * @param {any} id Category id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + unlinkRooms(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Check the existence of rooms relation to an item by id. + * + * @param {any} id Category id + * + * @param {any} fk Foreign key for rooms + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + existsRooms(id, fk, customHeaders) { + + let _method = "HEAD"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries rooms of Category. + * + * @param {any} id Category id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + getRooms(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in rooms of this model. + * + * @param {any} id Category id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + createRooms(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all rooms of this model. + * + * @param {any} id Category id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteRooms(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts rooms of Category. + * + * @param {any} id Category id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countRooms(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id Category id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Category registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in rooms of this model. + * + * @param {any} id Category id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Category` object.) + * + */ + createManyRooms(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/categories/:id/rooms"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `Category`. + */ + getModelName() { + return "Category"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/Core.js b/tests/react-web/app/shared/sdk/services/custom/Core.js new file mode 100644 index 00000000..42696485 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Core.js @@ -0,0 +1,102 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Core } from '../../models/Core'; + + +/** + * Api services for the `Core` model. + */ + +export class CoreApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/cores/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Core registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Core` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/cores/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `Core`. + */ + getModelName() { + return "Core"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/Like.js b/tests/react-web/app/shared/sdk/services/custom/Like.js new file mode 100644 index 00000000..0c617356 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Like.js @@ -0,0 +1,238 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Like } from '../../models/Like'; +import { Message } from '../../models/Message'; +import { Room } from '../../models/Room'; + + +/** + * Api services for the `Like` model. + */ + +export class LikeApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Fetches belongsTo relation message. + * + * @param {any} id like id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Like` object.) + * + */ + getMessage(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/likes/:id/message"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Fetches belongsTo relation room. + * + * @param {any} id like id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Like` object.) + * + */ + getRoom(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/likes/:id/room"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Like` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/likes"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id like id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Like` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/likes/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/likes/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Like registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Like` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/likes/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `Like`. + */ + getModelName() { + return "Like"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/Message.js b/tests/react-web/app/shared/sdk/services/custom/Message.js new file mode 100644 index 00000000..50413131 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Message.js @@ -0,0 +1,770 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Message } from '../../models/Message'; +import { Like } from '../../models/Like'; +import { Room } from '../../models/Room'; + + +/** + * Api services for the `Message` model. + */ + +export class MessageApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Find a related item by id for likes. + * + * @param {any} id Message id + * + * @param {any} fk Foreign key for likes + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + findByIdLikes(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for likes. + * + * @param {any} id Message id + * + * @param {any} fk Foreign key for likes + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdLikes(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for likes. + * + * @param {any} id Message id + * + * @param {any} fk Foreign key for likes + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + updateByIdLikes(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for replies. + * + * @param {any} id Message id + * + * @param {any} fk Foreign key for replies + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + findByIdReplies(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for replies. + * + * @param {any} id Message id + * + * @param {any} fk Foreign key for replies + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdReplies(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for replies. + * + * @param {any} id Message id + * + * @param {any} fk Foreign key for replies + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + updateByIdReplies(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Fetches belongsTo relation parent. + * + * @param {any} id Message id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + getParent(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/parent"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Fetches belongsTo relation room. + * + * @param {any} id Message id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + getRoom(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/room"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries likes of Message. + * + * @param {any} id Message id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + getLikes(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in likes of this model. + * + * @param {any} id Message id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + createLikes(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all likes of this model. + * + * @param {any} id Message id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteLikes(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts likes of Message. + * + * @param {any} id Message id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countLikes(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries replies of Message. + * + * @param {any} id Message id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + getReplies(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in replies of this model. + * + * @param {any} id Message id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + createReplies(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all replies of this model. + * + * @param {any} id Message id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteReplies(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts replies of Message. + * + * @param {any} id Message id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countReplies(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id Message id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Message registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in likes of this model. + * + * @param {any} id Message id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + createManyLikes(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in replies of this model. + * + * @param {any} id Message id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Message` object.) + * + */ + createManyReplies(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/messages/:id/replies"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `Message`. + */ + getModelName() { + return "Message"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/Room.js b/tests/react-web/app/shared/sdk/services/custom/Room.js new file mode 100644 index 00000000..c2c99d6b --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Room.js @@ -0,0 +1,2030 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Room } from '../../models/Room'; +import { Message } from '../../models/Message'; +import { Like } from '../../models/Like'; +import { Category } from '../../models/Category'; +import { RoomAccount } from '../../models/RoomAccount'; +import { Account } from '../../models/Account'; +import { RoomAdmin } from '../../models/RoomAdmin'; + + +/** + * Api services for the `Room` model. + */ + +export class RoomApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Find a related item by id for messages. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for messages + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByIdMessages(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for messages. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for messages + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdMessages(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for messages. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for messages + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + updateByIdMessages(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for likes. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for likes + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByIdLikes(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for likes. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for likes + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdLikes(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for likes. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for likes + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + updateByIdLikes(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for categories. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for categories + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByIdCategories(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for categories. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for categories + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdCategories(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for categories. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for categories + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + updateByIdCategories(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Add a related item by id for categories. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for categories + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + linkCategories(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Remove the categories relation to an item by id. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for categories + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + unlinkCategories(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Check the existence of categories relation to an item by id. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for categories + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + existsCategories(id, fk, customHeaders) { + + let _method = "HEAD"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for accounts. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for accounts + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByIdAccounts(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for accounts. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for accounts + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdAccounts(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for accounts. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for accounts + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + updateByIdAccounts(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Add a related item by id for accounts. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for accounts + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + linkAccounts(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Remove the accounts relation to an item by id. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for accounts + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + unlinkAccounts(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Check the existence of accounts relation to an item by id. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for accounts + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + existsAccounts(id, fk, customHeaders) { + + let _method = "HEAD"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Find a related item by id for admins. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for admins + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByIdAdmins(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for admins. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for admins + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdAdmins(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for admins. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for admins + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + updateByIdAdmins(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Add a related item by id for admins. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for admins + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + linkAdmins(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Remove the admins relation to an item by id. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for admins + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + unlinkAdmins(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Check the existence of admins relation to an item by id. + * + * @param {any} id Room id + * + * @param {any} fk Foreign key for admins + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + existsAdmins(id, fk, customHeaders) { + + let _method = "HEAD"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/rel/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries messages of Room. + * + * @param {any} id Room id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + getMessages(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in messages of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createMessages(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all messages of this model. + * + * @param {any} id Room id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteMessages(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts messages of Room. + * + * @param {any} id Room id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countMessages(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries likes of Room. + * + * @param {any} id Room id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + getLikes(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in likes of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createLikes(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all likes of this model. + * + * @param {any} id Room id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteLikes(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts likes of Room. + * + * @param {any} id Room id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countLikes(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries categories of Room. + * + * @param {any} id Room id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + getCategories(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in categories of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createCategories(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all categories of this model. + * + * @param {any} id Room id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteCategories(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts categories of Room. + * + * @param {any} id Room id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countCategories(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries accounts of Room. + * + * @param {any} id Room id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + getAccounts(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in accounts of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createAccounts(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all accounts of this model. + * + * @param {any} id Room id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteAccounts(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts accounts of Room. + * + * @param {any} id Room id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countAccounts(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries admins of Room. + * + * @param {any} id Room id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + getAdmins(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in admins of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createAdmins(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all admins of this model. + * + * @param {any} id Room id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteAdmins(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts admins of Room. + * + * @param {any} id Room id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countAdmins(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} a + * + * @param {string} b + * + * @param {string} c + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `greeting` – `{string}` - + */ + greetRoute(a, b, c, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/what/:a/:b/:c"; + let _routeParams = { + a: a, + b: b, + c: c + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} a + * + * @param {string} b + * + * @param {string} c + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `greeting` – `{string}` - + */ + greetGet(a, b, c, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/slimshady"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof a !== 'undefined' && a !== null) _urlParams.a = a; + if (typeof b !== 'undefined' && b !== null) _urlParams.b = b; + if (typeof c !== 'undefined' && c !== null) _urlParams.c = c; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {object} data Request data. + * + * - `a` – `{object}` - + * + * - `b` – `{object}` - + * + * - `c` – `{object}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `greeting` – `{object}` - + */ + greetPost(a, b, c, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/who"; + let _routeParams = {}; + let _postBody = { + a: a, + b: b, + c: c + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByRoom(room, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/findByRoom"; + let _routeParams = {}; + let _postBody = { + room: room + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result.map((instance: Room) => new Room(instance)); + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {object} data Request data. + * + * - `room` – `{object}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + findByRoomContext(room, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/findByRoomContext"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof room !== 'undefined' && room !== null) _urlParams.room = room; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result.map((instance: Room) => new Room(instance)); + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + singleParamPost(param, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/single-param-post"; + let _routeParams = {}; + let _postBody = { + param: param + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Gets list of all unique values used for a given property. + * + * @param {string} property Property name to lookup values for. + * + * @param {object} filter Filter defining fields, where, include, order, offset, and limit + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + getPropertyValues(property, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/propertyValues"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof property !== 'undefined' && property !== null) _urlParams.property = property; + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Room registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in messages of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createManyMessages(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/messages"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in likes of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createManyLikes(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/likes"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in categories of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createManyCategories(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/categories"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in accounts of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createManyAccounts(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/accounts"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in admins of this model. + * + * @param {any} id Room id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Room` object.) + * + */ + createManyAdmins(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/rooms/:id/admins"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `Room`. + */ + getModelName() { + return "Room"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/RoomAccount.js b/tests/react-web/app/shared/sdk/services/custom/RoomAccount.js new file mode 100644 index 00000000..c36d255d --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/RoomAccount.js @@ -0,0 +1,238 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { RoomAccount } from '../../models/RoomAccount'; +import { Account } from '../../models/Account'; +import { Room } from '../../models/Room'; + + +/** + * Api services for the `RoomAccount` model. + */ + +export class RoomAccountApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Fetches belongsTo relation account. + * + * @param {any} id RoomAccount id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAccount` object.) + * + */ + getAccount(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-accounts/:id/account"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Fetches belongsTo relation room. + * + * @param {any} id RoomAccount id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAccount` object.) + * + */ + getRoom(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-accounts/:id/room"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAccount` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-accounts"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id RoomAccount id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAccount` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-accounts/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-accounts/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for RoomAccount registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAccount` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-accounts/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `RoomAccount`. + */ + getModelName() { + return "RoomAccount"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/RoomAdmin.js b/tests/react-web/app/shared/sdk/services/custom/RoomAdmin.js new file mode 100644 index 00000000..777b34c4 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/RoomAdmin.js @@ -0,0 +1,238 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { RoomAdmin } from '../../models/RoomAdmin'; +import { Account } from '../../models/Account'; +import { Room } from '../../models/Room'; + + +/** + * Api services for the `RoomAdmin` model. + */ + +export class RoomAdminApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Fetches belongsTo relation account. + * + * @param {any} id RoomAdmin id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAdmin` object.) + * + */ + getAccount(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-admins/:id/account"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Fetches belongsTo relation room. + * + * @param {any} id RoomAdmin id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAdmin` object.) + * + */ + getRoom(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-admins/:id/room"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAdmin` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-admins"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id RoomAdmin id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAdmin` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-admins/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-admins/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for RoomAdmin registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `RoomAdmin` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/room-admins/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `RoomAdmin`. + */ + getModelName() { + return "RoomAdmin"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/SDKModels.js b/tests/react-web/app/shared/sdk/services/custom/SDKModels.js new file mode 100644 index 00000000..43304de2 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/SDKModels.js @@ -0,0 +1,43 @@ +import { User } from '../../models/User'; +import { Account } from '../../models/Account'; +import { ApplicationCredential } from '../../models/ApplicationCredential'; +import { Category } from '../../models/Category'; +import { Core } from '../../models/Core'; +import { Like } from '../../models/Like'; +import { Message } from '../../models/Message'; +import { Room } from '../../models/Room'; +import { RoomAccount } from '../../models/RoomAccount'; +import { RoomAdmin } from '../../models/RoomAdmin'; +import { Storage } from '../../models/Storage'; +import { UserCredential } from '../../models/UserCredential'; +import { UserIdentity } from '../../models/UserIdentity'; +export class SDKModels { + models = { + User: User, + Account: Account, + ApplicationCredential: ApplicationCredential, + Category: Category, + Core: Core, + Like: Like, + Message: Message, + Room: Room, + RoomAccount: RoomAccount, + RoomAdmin: RoomAdmin, + Storage: Storage, + UserCredential: UserCredential, + UserIdentity: UserIdentity, + + }; + + get(modelName) { + return this.models[modelName]; + } + + getAll() { + return this.models; + } + + getModelNames() { + return Object.keys(this.models); + } +} diff --git a/tests/react-web/app/shared/sdk/services/custom/Storage.js b/tests/react-web/app/shared/sdk/services/custom/Storage.js new file mode 100644 index 00000000..7d931b63 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/Storage.js @@ -0,0 +1,401 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { Storage } from '../../models/Storage'; + + +/** + * Api services for the `Storage` model. + */ + +export class StorageApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Storage` object.) + * + */ + getContainers(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Storage` object.) + * + */ + createContainer(options, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages"; + let _routeParams = {}; + let _postBody = { + options: options + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `` – `{}` - + */ + destroyContainer(container, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container"; + let _routeParams = { + container: container + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Storage` object.) + * + */ + getContainer(container, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container"; + let _routeParams = { + container: container + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Storage` object.) + * + */ + getFiles(container, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container/files"; + let _routeParams = { + container: container + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @param {string} file + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Storage` object.) + * + */ + getFile(container, file, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container/files/:file"; + let _routeParams = { + container: container, + file: file + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @param {string} file + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `` – `{}` - + */ + removeFile(container, file, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container/files/:file"; + let _routeParams = { + container: container, + file: file + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @param {object} data Request data. + * + * - `req` – `{object}` - + * + * - `res` – `{object}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{object}` - + */ + upload(container, req, res, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container/upload"; + let _routeParams = { + container: container + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @param {string} container + * + * @param {string} file + * + * @param {object} req + * + * @param {object} res + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + download(container, file, req, res, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/:container/download/:file"; + let _routeParams = { + container: container, + file: file + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for Storage registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `Storage` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/storages/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `Storage`. + */ + getModelName() { + return "Storage"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/User.js b/tests/react-web/app/shared/sdk/services/custom/User.js new file mode 100644 index 00000000..60df4682 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/User.js @@ -0,0 +1,672 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, SDKToken, AccessToken } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { User } from '../../models/User'; + + +/** + * Api services for the `User` model. + */ + +export class UserApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Find a related item by id for accessTokens. + * + * @param {any} id User id + * + * @param {any} fk Foreign key for accessTokens + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + findByIdAccessTokens(id, fk, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Delete a related item by id for accessTokens. + * + * @param {any} id User id + * + * @param {any} fk Foreign key for accessTokens + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + destroyByIdAccessTokens(id, fk, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Update a related item by id for accessTokens. + * + * @param {any} id User id + * + * @param {any} fk Foreign key for accessTokens + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + updateByIdAccessTokens(id, fk, data, customHeaders) { + + let _method = "PUT"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens/:fk"; + let _routeParams = { + id: id, + fk: fk + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Queries accessTokens of User. + * + * @param {any} id User id + * + * @param {object} filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + getAccessTokens(id, filter, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof filter !== 'undefined' && filter !== null) _urlParams.filter = filter; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in accessTokens of this model. + * + * @param {any} id User id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + createAccessTokens(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Deletes all accessTokens of this model. + * + * @param {any} id User id + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + deleteAccessTokens(id, customHeaders) { + + let _method = "DELETE"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Counts accessTokens of User. + * + * @param {any} id User id + * + * @param {object} where Criteria to match model instances + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `count` – `{number}` - + */ + countAccessTokens(id, where, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens/count"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id User id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Login a user with username/email and password. + * + * @param {string} include Related objects to include in the response. See the description of return value for more details. + * Default value: `user`. + * + * - `rememberMe` - `boolean` - Whether the authentication credentials + * should be remembered in localStorage across app/browser restarts. + * Default: `true`. + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * The response body contains properties of the AccessToken created on login. + * Depending on the value of `include` parameter, the body may contain additional properties: + * + * - `user` - `U+007BUserU+007D` - Data of the currently logged in user. (`include=user`) + * + * + */ + login(credentials, include, rememberMe = true, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/login"; + let _routeParams = {}; + let _postBody = { + credentials: credentials + }; + let _urlParams = {}; + + + if (typeof include !== 'undefined' && include !== null) _urlParams.include = include; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders) + .map( + (response) => { + response.ttl = parseInt(response.ttl); + response.rememberMe = rememberMe; + this.auth.setToken(response); + return response; + } + ); + return result; + + } + + /** + * Logout a user with access token. + * + * @param {object} data Request data. + * + * This method does not accept any data. Supply an empty object. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + logout(customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/logout"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + _urlParams.access_token = this.auth.getAccessTokenId(); + this.auth.clear(); + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Trigger user's identity verification with configured verifyOptions + * + * @param {any} id User id + * + * @param {object} data Request data. + * + * This method does not accept any data. Supply an empty object. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + verify(id, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/verify"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Confirm a user registration with identity verification token. + * + * @param {string} uid + * + * @param {string} token + * + * @param {string} redirect + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + confirm(uid, token, redirect, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/confirm"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof uid !== 'undefined' && uid !== null) _urlParams.uid = uid; + if (typeof token !== 'undefined' && token !== null) _urlParams.token = token; + if (typeof redirect !== 'undefined' && redirect !== null) _urlParams.redirect = redirect; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Reset password for a user with email. + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + resetPassword(options, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/reset"; + let _routeParams = {}; + let _postBody = { + options: options + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Change a user's password. + * + * @param {object} data Request data. + * + * - `oldPassword` – `{string}` - + * + * - `newPassword` – `{string}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + changePassword(oldPassword, newPassword, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/change-password"; + let _routeParams = {}; + let _postBody = { + data: { + oldPassword: oldPassword, + newPassword: newPassword + } + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Reset user's password via a password-reset token. + * + * @param {object} data Request data. + * + * - `newPassword` – `{string}` - + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * This method returns no data. + */ + setPassword(newPassword, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/reset-password"; + let _routeParams = {}; + let _postBody = { + data: { + newPassword: newPassword + } + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Creates a new instance in accessTokens of this model. + * + * @param {any} id User id + * + * @param {object} data Request data. + * + * This method expects a subset of model properties as request parameters. + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `User` object.) + * + */ + createManyAccessTokens(id, data, customHeaders) { + + let _method = "POST"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/Users/:id/accessTokens"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + /** + * @ngdoc method + * @name sdk.User#getCurrent + * @methodOf sdk.User + * + * @description + * + * Get data of the currently logged user. Fail with HTTP result 401 + * when there is no user logged in. + * + * @returns object An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + */ + getCurrent(filter = {}) { + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + "/Users" + "/:id"; + let id = this.auth.getCurrentUserId(); + if (id == null) + id = '__anonymous__'; + let _routeParams = { id: id }; + let _urlParams = {}; + let _postBody = {}; + if (filter) _urlParams.filter = filter; + return this.request(_method, _url, _routeParams, _urlParams, _postBody); + } + /** + * Get data of the currently logged user that was returned by the last + * call to {@link sdk.User#login} or + * {@link sdk.User#getCurrent}. Return null when there + * is no user logged in or the data of the current user were not fetched + * yet. + * + * @returns object An Account instance. + */ + getCachedCurrent() { + return this.auth.getCurrentUserData(); + } + /** + * Get data of the currently logged access tokern that was returned by the last + * call to {@link sdk.User#login} + * + * @returns object An AccessToken instance. + */ + getCurrentToken() { + return this.auth.getToken(); + } + /** + * @name sdk.User#isAuthenticated + * + * @returns {boolean} True if the current user is authenticated (logged in). + */ + isAuthenticated() { + return !(this.getCurrentId() === '' || this.getCurrentId() == null || this.getCurrentId() == 'null'); + } + + /** + * @name sdk.User#getCurrentId + * + * @returns object Id of the currently logged-in user or null. + */ + getCurrentId() { + return this.auth.getCurrentUserId(); + } + + /** + * The name of the model represented by this $resource, + * i.e. `User`. + */ + getModelName() { + return "User"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/UserCredential.js b/tests/react-web/app/shared/sdk/services/custom/UserCredential.js new file mode 100644 index 00000000..3f817f09 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/UserCredential.js @@ -0,0 +1,170 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { UserCredential } from '../../models/UserCredential'; + + +/** + * Api services for the `UserCredential` model. + */ + +export class UserCredentialApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserCredential` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-credentials"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id UserCredential id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserCredential` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-credentials/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-credentials/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for UserCredential registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserCredential` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-credentials/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `UserCredential`. + */ + getModelName() { + return "UserCredential"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/UserIdentity.js b/tests/react-web/app/shared/sdk/services/custom/UserIdentity.js new file mode 100644 index 00000000..785405a2 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/UserIdentity.js @@ -0,0 +1,204 @@ +/* tslint:disable */ +import { SDKModels } from './SDKModels'; +import { BaseLoopBackApi } from '../core/base.service'; +import { LoopBackConfig } from '../../lb.config'; +import { LoopBackFilter, } from '../../models/BaseModels'; +import { JSONSearchParams } from '../core/search.params'; +import { ErrorHandler } from '../core/error.service'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Rx'; +import { UserIdentity } from '../../models/UserIdentity'; +import { User } from '../../models/User'; + + +/** + * Api services for the `UserIdentity` model. + */ + +export class UserIdentityApi extends BaseLoopBackApi { + + constructor( + + ) { + + super(); + + } + + /** + * Fetches belongsTo relation user. + * + * @param {any} id UserIdentity id + * + * @param {boolean} refresh + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserIdentity` object.) + * + */ + getUser(id, refresh, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-identities/:id/user"; + let _routeParams = { + id: id + }; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof refresh !== 'undefined' && refresh !== null) _urlParams.refresh = refresh; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch an existing model instance or insert a new one into the data source. + * + * @param {object} data Request data. + * + * - `data` – `{object}` - Model instance data + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserIdentity` object.) + * + */ + patchOrCreate(data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-identities"; + let _routeParams = {}; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Patch attributes for a model instance and persist it into the data source. + * + * @param {any} id UserIdentity id + * + * @param {object} data Request data. + * + * - `data` – `{object}` - An object of model property name/value pairs + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserIdentity` object.) + * + */ + patchAttributes(id, data, customHeaders) { + + let _method = "PATCH"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-identities/:id"; + let _routeParams = { + id: id + }; + let _postBody = { + data: data + }; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * + * (The remote method definition does not provide any description.) + * + * + * @returns {object} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * Data properties: + * + * - `result` – `{any}` - + */ + myRemote(customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-identities/my-remote"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + /** + * Statistical information for UserIdentity registers. + * + * @param {string} range hourly, daily, weekly, monthly, yearly, custom + * + * @param {object} custom {"start": date, "end": date } + * + * @param {object} where where filter + * + * @param {string} groupBy group by filter + * + * @returns {object[]} An empty reference that will be + * populated with the actual data once the response is returned + * from the server. + * + * + * (The remote method definition does not provide any description. + * This usually means the response is a `UserIdentity` object.) + * + */ + stats(range, custom, where, groupBy, customHeaders) { + + let _method = "GET"; + let _url = LoopBackConfig.getPath() + "/" + LoopBackConfig.getApiVersion() + + "/user-identities/stats"; + let _routeParams = {}; + let _postBody = {}; + let _urlParams = {}; + + + if (typeof range !== 'undefined' && range !== null) _urlParams.range = range; + if (typeof custom !== 'undefined' && custom !== null) _urlParams.custom = custom; + if (typeof where !== 'undefined' && where !== null) _urlParams.where = where; + if (typeof groupBy !== 'undefined' && groupBy !== null) _urlParams.groupBy = groupBy; + let result = this.request(_method, _url, _routeParams, _urlParams, _postBody, null, customHeaders); + return result; + } + + + + /** + * The name of the model represented by this $resource, + * i.e. `UserIdentity`. + */ + getModelName() { + return "UserIdentity"; + } +} + diff --git a/tests/react-web/app/shared/sdk/services/custom/index.js b/tests/react-web/app/shared/sdk/services/custom/index.js new file mode 100644 index 00000000..e25e5fd3 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/index.js @@ -0,0 +1,16 @@ +/* tslint:disable */ +export * from './User'; +export * from './Account'; +export * from './ApplicationCredential'; +export * from './Category'; +export * from './Core'; +export * from './Like'; +export * from './Message'; +export * from './Room'; +export * from './RoomAccount'; +export * from './RoomAdmin'; +export * from './Storage'; +export * from './UserCredential'; +export * from './UserIdentity'; +export * from './SDKModels'; +export * from './logger.service'; diff --git a/tests/react-web/app/shared/sdk/services/custom/logger.service.js b/tests/react-web/app/shared/sdk/services/custom/logger.service.js new file mode 100644 index 00000000..6170211b --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/custom/logger.service.js @@ -0,0 +1,62 @@ + +import { LoopBackConfig } from '../../lb.config'; +/** +* @author Jonathan Casarrubias +* @module LoggerService +* @license MIT +* @description +* Console Log wrapper that can be disabled in production mode +**/ + +export class LoggerService { + + log(...args) { + if (LoopBackConfig.debuggable()) + console.log.apply(console, args); + } + + info(...args) { + if (LoopBackConfig.debuggable()) + console.info.apply(console, args); + } + + error(...args) { + if (LoopBackConfig.debuggable()) + console.error.apply(console, args); + } + + count(arg) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + group(arg) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + groupEnd() { + if (LoopBackConfig.debuggable()) + console.groupEnd(); + } + + profile(arg) { + if (LoopBackConfig.debuggable()) + console.count(arg); + } + + profileEnd() { + if (LoopBackConfig.debuggable()) + console.profileEnd(); + } + + time(arg) { + if (LoopBackConfig.debuggable()) + console.time(arg); + } + + timeEnd(arg) { + if (LoopBackConfig.debuggable()) + console.timeEnd(arg); + } +} diff --git a/tests/react-web/app/shared/sdk/services/index.js b/tests/react-web/app/shared/sdk/services/index.js new file mode 100644 index 00000000..bd1dcfa6 --- /dev/null +++ b/tests/react-web/app/shared/sdk/services/index.js @@ -0,0 +1,3 @@ +/* tslint:disable */ +export * from './core/index'; +export * from './custom/index'; diff --git a/tests/react-web/app/shared/sdk/storage/cookie.browser.js b/tests/react-web/app/shared/sdk/storage/cookie.browser.js new file mode 100644 index 00000000..de498373 --- /dev/null +++ b/tests/react-web/app/shared/sdk/storage/cookie.browser.js @@ -0,0 +1,79 @@ + +/** +* @author Jonathan Casarrubias +* @module CookieBrowser +* @license MIT +* @description +* This module handle cookies, it will be provided using DI Swapping according the +* SDK Socket Driver Available currently supporting Angular 2 for web and NativeScript 2. +**/ + +export class CookieBrowser { + + /** + * @type {CookieInterface} + **/ + cookies = {}; + /** + * @method get + * @param {string} key Cookie key name + * @return {any} + * @description + * The getter will return any type of data persisted in cookies. + **/ + get(key) { + if (!this.cookies[key]) { + let cookie = window.document + .cookie.split('; ') + .filter((item) => item.split('=')[0] === key).pop(); + if (!cookie) { + return null; + } + + this.cookies[key] = this.parse(cookie.split('=').slice(1).join('=')); + } + + return this.cookies[key]; + } + /** + * @method set + * @param {string} key Cookie key name + * @param {any} value Any value + * @param {Date=} expires The date of expiration (Optional) + * @return {void} + * @description + * The setter will return any type of data persisted in cookies. + **/ + set(key, value, expires) { + this.cookies[key] = value; + let cookie = `${key}=${value}; path=/${expires ? `; expires=${ expires.toUTCString() }` : ''}`; + window.document.cookie = cookie; + } + /** + * @method remove + * @param {string} key Cookie key name + * @return {void} + * @description + * This method will remove a cookie from the client. + **/ + remove(key) { + document.cookie = key + '=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + delete this.cookies[key]; + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + parse(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + +} diff --git a/tests/react-web/app/shared/sdk/storage/storage.browser.js b/tests/react-web/app/shared/sdk/storage/storage.browser.js new file mode 100644 index 00000000..6b13edfb --- /dev/null +++ b/tests/react-web/app/shared/sdk/storage/storage.browser.js @@ -0,0 +1,68 @@ + +/** +* @author Jonathan Casarrubias +* @module StorageBrowser +* @license MIT +* @description +* This module handle localStorage, it will be provided using DI Swapping according the +* SDK Socket Driver Available currently supporting Angular 2 for web and NativeScript 2. +**/ + +export class StorageBrowser { + + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in localStorage. + **/ + get(key){ + let data = localStorage.getItem(key); + return this.parse(data); + } + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key, value) { + localStorage.setItem( + key, + typeof value === 'object' ? JSON.stringify(value) : value + ); + } + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key) { + if (localStorage[key]) { + localStorage.removeItem(key); + } else { + console.log('Trying to remove unexisting key: ', key); + } + } + /** + * @method parse + * @param {any} value Input data expected to be JSON + * @return {void} + * @description + * This method will parse the string as JSON if possible, otherwise will + * return the value itself. + **/ + parse(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + +} diff --git a/tests/react-web/app/shared/sdk/storage/storage.swaps.js b/tests/react-web/app/shared/sdk/storage/storage.swaps.js new file mode 100644 index 00000000..3e81566f --- /dev/null +++ b/tests/react-web/app/shared/sdk/storage/storage.swaps.js @@ -0,0 +1,58 @@ +/** + * @module Storage + * @author Jonathan Casarrubias + * @license MIT + * @description + * The InternalStorage class is used for dependency injection swapping. + * It will be provided using factory method from different sources. + **/ +export class BaseStorage { + /** + * @method get + * @param {string} key Storage key name + * @return {any} + * @description + * The getter will return any type of data persisted in storage. + **/ + get(key) {} + /** + * @method set + * @param {string} key Storage key name + * @param {any} value Any value + * @return {void} + * @description + * The setter will return any type of data persisted in localStorage. + **/ + set(key, value) {} + /** + * @method remove + * @param {string} key Storage key name + * @return {void} + * @description + * This method will remove a localStorage item from the client. + **/ + remove(key) {} +} + +/** + * @module InternalStorage + * @author Jonathan Casarrubias + * @license MIT + * @description + * The InternalStorage class is used for dependency injection swapping. + * It will be provided using factory method from different sources. + * This is mainly required because Angular Universal integration. + * It does inject a CookieStorage instead of LocalStorage. + **/ +export class InternalStorage extends BaseStorage {} +/** + * @module SDKStorage + * @author Jonathan Casarrubias + * @license MIT + * @description + * The SDKStorage class is used for dependency injection swapping. + * It will be provided using factory method according the right environment. + * This is created for public usage, to allow persisting custom data + * Into the local storage API. + **/ +export class SDKStorage extends BaseStorage {} diff --git a/tests/react-web/bundle.js b/tests/react-web/bundle.js new file mode 100644 index 00000000..85b2375e --- /dev/null +++ b/tests/react-web/bundle.js @@ -0,0 +1,54212 @@ +/******/ (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] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = 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; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var _react = __webpack_require__(1); + + var _react2 = _interopRequireDefault(_react); + + var _reactDom = __webpack_require__(34); + + var _App = __webpack_require__(172); + + var _App2 = _interopRequireDefault(_App); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + (0, _reactDom.render)(_react2.default.createElement(_App2.default, null), document.getElementById('app')); + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + module.exports = __webpack_require__(2); + + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule React + */ + + 'use strict'; + + var _assign = __webpack_require__(4); + + var ReactChildren = __webpack_require__(5); + var ReactComponent = __webpack_require__(17); + var ReactPureComponent = __webpack_require__(20); + var ReactClass = __webpack_require__(21); + var ReactDOMFactories = __webpack_require__(26); + var ReactElement = __webpack_require__(9); + var ReactPropTypes = __webpack_require__(31); + var ReactVersion = __webpack_require__(32); + + var onlyChild = __webpack_require__(33); + var warning = __webpack_require__(11); + + var createElement = ReactElement.createElement; + var createFactory = ReactElement.createFactory; + var cloneElement = ReactElement.cloneElement; + + if (process.env.NODE_ENV !== 'production') { + var ReactElementValidator = __webpack_require__(27); + createElement = ReactElementValidator.createElement; + createFactory = ReactElementValidator.createFactory; + cloneElement = ReactElementValidator.cloneElement; + } + + var __spread = _assign; + + if (process.env.NODE_ENV !== 'production') { + var warned = false; + __spread = function () { + process.env.NODE_ENV !== 'production' ? warning(warned, 'React.__spread is deprecated and should not be used. Use ' + 'Object.assign directly or another helper function with similar ' + 'semantics. You may be seeing this warning due to your compiler. ' + 'See https://fb.me/react-spread-deprecation for more details.') : void 0; + warned = true; + return _assign.apply(null, arguments); + }; + } + + var React = { + + // Modern + + Children: { + map: ReactChildren.map, + forEach: ReactChildren.forEach, + count: ReactChildren.count, + toArray: ReactChildren.toArray, + only: onlyChild + }, + + Component: ReactComponent, + PureComponent: ReactPureComponent, + + createElement: createElement, + cloneElement: cloneElement, + isValidElement: ReactElement.isValidElement, + + // Classic + + PropTypes: ReactPropTypes, + createClass: ReactClass.createClass, + createFactory: createFactory, + createMixin: function (mixin) { + // Currently a noop. Will be used to validate and trace mixins. + return mixin; + }, + + // This looks DOM specific but these are actually isomorphic helpers + // since they are just generating DOM strings. + DOM: ReactDOMFactories, + + version: ReactVersion, + + // Deprecated hook for JSX spread, don't use this for anything. + __spread: __spread + }; + + module.exports = React; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 3 */ +/***/ 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; }; + + +/***/ }, +/* 4 */ +/***/ function(module, exports) { + + /* + object-assign + (c) Sindre Sorhus + @license MIT + */ + + 'use strict'; + /* 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; + }; + + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactChildren + */ + + 'use strict'; + + var PooledClass = __webpack_require__(6); + var ReactElement = __webpack_require__(9); + + var emptyFunction = __webpack_require__(12); + var traverseAllChildren = __webpack_require__(14); + + var twoArgumentPooler = PooledClass.twoArgumentPooler; + var fourArgumentPooler = PooledClass.fourArgumentPooler; + + var userProvidedKeyEscapeRegex = /\/+/g; + function escapeUserProvidedKey(text) { + return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/'); + } + + /** + * PooledClass representing the bookkeeping associated with performing a child + * traversal. Allows avoiding binding callbacks. + * + * @constructor ForEachBookKeeping + * @param {!function} forEachFunction Function to perform traversal with. + * @param {?*} forEachContext Context to perform context with. + */ + function ForEachBookKeeping(forEachFunction, forEachContext) { + this.func = forEachFunction; + this.context = forEachContext; + this.count = 0; + } + ForEachBookKeeping.prototype.destructor = function () { + this.func = null; + this.context = null; + this.count = 0; + }; + PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler); + + function forEachSingleChild(bookKeeping, child, name) { + var func = bookKeeping.func; + var context = bookKeeping.context; + + func.call(context, child, bookKeeping.count++); + } + + /** + * Iterates through children that are typically specified as `props.children`. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.foreach + * + * The provided forEachFunc(child, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} forEachFunc + * @param {*} forEachContext Context for forEachContext. + */ + function forEachChildren(children, forEachFunc, forEachContext) { + if (children == null) { + return children; + } + var traverseContext = ForEachBookKeeping.getPooled(forEachFunc, forEachContext); + traverseAllChildren(children, forEachSingleChild, traverseContext); + ForEachBookKeeping.release(traverseContext); + } + + /** + * PooledClass representing the bookkeeping associated with performing a child + * mapping. Allows avoiding binding callbacks. + * + * @constructor MapBookKeeping + * @param {!*} mapResult Object containing the ordered map of results. + * @param {!function} mapFunction Function to perform mapping with. + * @param {?*} mapContext Context to perform mapping with. + */ + function MapBookKeeping(mapResult, keyPrefix, mapFunction, mapContext) { + this.result = mapResult; + this.keyPrefix = keyPrefix; + this.func = mapFunction; + this.context = mapContext; + this.count = 0; + } + MapBookKeeping.prototype.destructor = function () { + this.result = null; + this.keyPrefix = null; + this.func = null; + this.context = null; + this.count = 0; + }; + PooledClass.addPoolingTo(MapBookKeeping, fourArgumentPooler); + + function mapSingleChildIntoContext(bookKeeping, child, childKey) { + var result = bookKeeping.result; + var keyPrefix = bookKeeping.keyPrefix; + var func = bookKeeping.func; + var context = bookKeeping.context; + + + var mappedChild = func.call(context, child, bookKeeping.count++); + if (Array.isArray(mappedChild)) { + mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, emptyFunction.thatReturnsArgument); + } else if (mappedChild != null) { + if (ReactElement.isValidElement(mappedChild)) { + mappedChild = ReactElement.cloneAndReplaceKey(mappedChild, + // Keep both the (mapped) and old keys if they differ, just as + // traverseAllChildren used to do for objects as children + keyPrefix + (mappedChild.key && (!child || child.key !== mappedChild.key) ? escapeUserProvidedKey(mappedChild.key) + '/' : '') + childKey); + } + result.push(mappedChild); + } + } + + function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { + var escapedPrefix = ''; + if (prefix != null) { + escapedPrefix = escapeUserProvidedKey(prefix) + '/'; + } + var traverseContext = MapBookKeeping.getPooled(array, escapedPrefix, func, context); + traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); + MapBookKeeping.release(traverseContext); + } + + /** + * Maps children that are typically specified as `props.children`. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.map + * + * The provided mapFunction(child, key, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} func The map function. + * @param {*} context Context for mapFunction. + * @return {object} Object containing the ordered map of results. + */ + function mapChildren(children, func, context) { + if (children == null) { + return children; + } + var result = []; + mapIntoWithKeyPrefixInternal(children, result, null, func, context); + return result; + } + + function forEachSingleChildDummy(traverseContext, child, name) { + return null; + } + + /** + * Count the number of children that are typically specified as + * `props.children`. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.count + * + * @param {?*} children Children tree container. + * @return {number} The number of children. + */ + function countChildren(children, context) { + return traverseAllChildren(children, forEachSingleChildDummy, null); + } + + /** + * Flatten a children object (typically specified as `props.children`) and + * return an array with appropriately re-keyed children. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.toarray + */ + function toArray(children) { + var result = []; + mapIntoWithKeyPrefixInternal(children, result, null, emptyFunction.thatReturnsArgument); + return result; + } + + var ReactChildren = { + forEach: forEachChildren, + map: mapChildren, + mapIntoWithKeyPrefixInternal: mapIntoWithKeyPrefixInternal, + count: countChildren, + toArray: toArray + }; + + module.exports = ReactChildren; + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule PooledClass + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var invariant = __webpack_require__(8); + + /** + * Static poolers. Several custom versions for each potential number of + * arguments. A completely generic pooler is easy to implement, but would + * require accessing the `arguments` object. In each of these, `this` refers to + * the Class itself, not an instance. If any others are needed, simply add them + * here, or in their own files. + */ + var oneArgumentPooler = function (copyFieldsFrom) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, copyFieldsFrom); + return instance; + } else { + return new Klass(copyFieldsFrom); + } + }; + + var twoArgumentPooler = function (a1, a2) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2); + return instance; + } else { + return new Klass(a1, a2); + } + }; + + var threeArgumentPooler = function (a1, a2, a3) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3); + return instance; + } else { + return new Klass(a1, a2, a3); + } + }; + + var fourArgumentPooler = function (a1, a2, a3, a4) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4); + return instance; + } else { + return new Klass(a1, a2, a3, a4); + } + }; + + var fiveArgumentPooler = function (a1, a2, a3, a4, a5) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4, a5); + return instance; + } else { + return new Klass(a1, a2, a3, a4, a5); + } + }; + + var standardReleaser = function (instance) { + var Klass = this; + !(instance instanceof Klass) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0; + instance.destructor(); + if (Klass.instancePool.length < Klass.poolSize) { + Klass.instancePool.push(instance); + } + }; + + var DEFAULT_POOL_SIZE = 10; + var DEFAULT_POOLER = oneArgumentPooler; + + /** + * Augments `CopyConstructor` to be a poolable class, augmenting only the class + * itself (statically) not adding any prototypical fields. Any CopyConstructor + * you give this may have a `poolSize` property, and will look for a + * prototypical `destructor` on instances. + * + * @param {Function} CopyConstructor Constructor that can be used to reset. + * @param {Function} pooler Customizable pooler. + */ + var addPoolingTo = function (CopyConstructor, pooler) { + var NewKlass = CopyConstructor; + NewKlass.instancePool = []; + NewKlass.getPooled = pooler || DEFAULT_POOLER; + if (!NewKlass.poolSize) { + NewKlass.poolSize = DEFAULT_POOL_SIZE; + } + NewKlass.release = standardReleaser; + return NewKlass; + }; + + var PooledClass = { + addPoolingTo: addPoolingTo, + oneArgumentPooler: oneArgumentPooler, + twoArgumentPooler: twoArgumentPooler, + threeArgumentPooler: threeArgumentPooler, + fourArgumentPooler: fourArgumentPooler, + fiveArgumentPooler: fiveArgumentPooler + }; + + module.exports = PooledClass; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 7 */ +/***/ function(module, exports) { + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule reactProdInvariant + * + */ + 'use strict'; + + /** + * WARNING: DO NOT manually require this module. + * This is a replacement for `invariant(...)` used by the error code system + * and will _only_ be required by the corresponding babel pass. + * It always throws. + */ + + function reactProdInvariant(code) { + var argCount = arguments.length - 1; + + var message = 'Minified React error #' + code + '; visit ' + 'http://facebook.github.io/react/docs/error-decoder.html?invariant=' + code; + + for (var argIdx = 0; argIdx < argCount; argIdx++) { + message += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]); + } + + message += ' for the full message or use the non-minified dev environment' + ' for full errors and additional helpful warnings.'; + + var error = new Error(message); + error.name = 'Invariant Violation'; + error.framesToPop = 1; // we don't care about reactProdInvariant's own frame + + throw error; + } + + module.exports = reactProdInvariant; + +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + 'use strict'; + + /** + * 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(format) {}; + + if (process.env.NODE_ENV !== 'production') { + validateFormat = function validateFormat(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; + 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; + } + } + + module.exports = invariant; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactElement + */ + + 'use strict'; + + var _assign = __webpack_require__(4); + + var ReactCurrentOwner = __webpack_require__(10); + + var warning = __webpack_require__(11); + var canDefineProperty = __webpack_require__(13); + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // The Symbol used to tag the ReactElement type. If there is no native Symbol + // nor polyfill, then a plain number is used for performance. + var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7; + + var RESERVED_PROPS = { + key: true, + ref: true, + __self: true, + __source: true + }; + + var specialPropKeyWarningShown, specialPropRefWarningShown; + + function hasValidRef(config) { + if (process.env.NODE_ENV !== 'production') { + if (hasOwnProperty.call(config, 'ref')) { + var getter = Object.getOwnPropertyDescriptor(config, 'ref').get; + if (getter && getter.isReactWarning) { + return false; + } + } + } + return config.ref !== undefined; + } + + function hasValidKey(config) { + if (process.env.NODE_ENV !== 'production') { + if (hasOwnProperty.call(config, 'key')) { + var getter = Object.getOwnPropertyDescriptor(config, 'key').get; + if (getter && getter.isReactWarning) { + return false; + } + } + } + return config.key !== undefined; + } + + function defineKeyPropWarningGetter(props, displayName) { + var warnAboutAccessingKey = function () { + if (!specialPropKeyWarningShown) { + specialPropKeyWarningShown = true; + process.env.NODE_ENV !== 'production' ? warning(false, '%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://fb.me/react-special-props)', displayName) : void 0; + } + }; + warnAboutAccessingKey.isReactWarning = true; + Object.defineProperty(props, 'key', { + get: warnAboutAccessingKey, + configurable: true + }); + } + + function defineRefPropWarningGetter(props, displayName) { + var warnAboutAccessingRef = function () { + if (!specialPropRefWarningShown) { + specialPropRefWarningShown = true; + process.env.NODE_ENV !== 'production' ? warning(false, '%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://fb.me/react-special-props)', displayName) : void 0; + } + }; + warnAboutAccessingRef.isReactWarning = true; + Object.defineProperty(props, 'ref', { + get: warnAboutAccessingRef, + configurable: true + }); + } + + /** + * Factory method to create a new React element. This no longer adheres to + * the class pattern, so do not use new to call it. Also, no instanceof check + * will work. Instead test $$typeof field against Symbol.for('react.element') to check + * if something is a React Element. + * + * @param {*} type + * @param {*} key + * @param {string|object} ref + * @param {*} self A *temporary* helper to detect places where `this` is + * different from the `owner` when React.createElement is called, so that we + * can warn. We want to get rid of owner and replace string `ref`s with arrow + * functions, and as long as `this` and owner are the same, there will be no + * change in behavior. + * @param {*} source An annotation object (added by a transpiler or otherwise) + * indicating filename, line number, and/or other information. + * @param {*} owner + * @param {*} props + * @internal + */ + var ReactElement = function (type, key, ref, self, source, owner, props) { + var element = { + // This tag allow us to uniquely identify this as a React Element + $$typeof: REACT_ELEMENT_TYPE, + + // Built-in properties that belong on the element + type: type, + key: key, + ref: ref, + props: props, + + // Record the component responsible for creating this element. + _owner: owner + }; + + if (process.env.NODE_ENV !== 'production') { + // The validation flag is currently mutative. We put it on + // an external backing store so that we can freeze the whole object. + // This can be replaced with a WeakMap once they are implemented in + // commonly used development environments. + element._store = {}; + var shadowChildren = Array.isArray(props.children) ? props.children.slice(0) : props.children; + + // To make comparing ReactElements easier for testing purposes, we make + // the validation flag non-enumerable (where possible, which should + // include every environment we run tests in), so the test framework + // ignores it. + if (canDefineProperty) { + Object.defineProperty(element._store, 'validated', { + configurable: false, + enumerable: false, + writable: true, + value: false + }); + // self and source are DEV only properties. + Object.defineProperty(element, '_self', { + configurable: false, + enumerable: false, + writable: false, + value: self + }); + Object.defineProperty(element, '_shadowChildren', { + configurable: false, + enumerable: false, + writable: false, + value: shadowChildren + }); + // Two elements created in two different places should be considered + // equal for testing purposes and therefore we hide it from enumeration. + Object.defineProperty(element, '_source', { + configurable: false, + enumerable: false, + writable: false, + value: source + }); + } else { + element._store.validated = false; + element._self = self; + element._shadowChildren = shadowChildren; + element._source = source; + } + if (Object.freeze) { + Object.freeze(element.props); + Object.freeze(element); + } + } + + return element; + }; + + /** + * Create and return a new ReactElement of the given type. + * See https://facebook.github.io/react/docs/top-level-api.html#react.createelement + */ + ReactElement.createElement = function (type, config, children) { + var propName; + + // Reserved names are extracted + var props = {}; + + var key = null; + var ref = null; + var self = null; + var source = null; + + if (config != null) { + if (hasValidRef(config)) { + ref = config.ref; + } + if (hasValidKey(config)) { + key = '' + config.key; + } + + self = config.__self === undefined ? null : config.__self; + source = config.__source === undefined ? null : config.__source; + // Remaining properties are added to a new props object + for (propName in config) { + if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { + props[propName] = config[propName]; + } + } + } + + // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + props.children = childArray; + } + + // Resolve default props + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; + for (propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } + } + } + if (process.env.NODE_ENV !== 'production') { + if (key || ref) { + if (typeof props.$$typeof === 'undefined' || props.$$typeof !== REACT_ELEMENT_TYPE) { + var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; + if (key) { + defineKeyPropWarningGetter(props, displayName); + } + if (ref) { + defineRefPropWarningGetter(props, displayName); + } + } + } + } + return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props); + }; + + /** + * Return a function that produces ReactElements of a given type. + * See https://facebook.github.io/react/docs/top-level-api.html#react.createfactory + */ + ReactElement.createFactory = function (type) { + var factory = ReactElement.createElement.bind(null, type); + // Expose the type on the factory and the prototype so that it can be + // easily accessed on elements. E.g. `.type === Foo`. + // This should not be named `constructor` since this may not be the function + // that created the element, and it may not even be a constructor. + // Legacy hook TODO: Warn if this is accessed + factory.type = type; + return factory; + }; + + ReactElement.cloneAndReplaceKey = function (oldElement, newKey) { + var newElement = ReactElement(oldElement.type, newKey, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, oldElement.props); + + return newElement; + }; + + /** + * Clone and return a new ReactElement using element as the starting point. + * See https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement + */ + ReactElement.cloneElement = function (element, config, children) { + var propName; + + // Original props are copied + var props = _assign({}, element.props); + + // Reserved names are extracted + var key = element.key; + var ref = element.ref; + // Self is preserved since the owner is preserved. + var self = element._self; + // Source is preserved since cloneElement is unlikely to be targeted by a + // transpiler, and the original source is probably a better indicator of the + // true owner. + var source = element._source; + + // Owner will be preserved, unless ref is overridden + var owner = element._owner; + + if (config != null) { + if (hasValidRef(config)) { + // Silently steal the ref from the parent. + ref = config.ref; + owner = ReactCurrentOwner.current; + } + if (hasValidKey(config)) { + key = '' + config.key; + } + + // Remaining properties override existing props + var defaultProps; + if (element.type && element.type.defaultProps) { + defaultProps = element.type.defaultProps; + } + for (propName in config) { + if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { + if (config[propName] === undefined && defaultProps !== undefined) { + // Resolve default props + props[propName] = defaultProps[propName]; + } else { + props[propName] = config[propName]; + } + } + } + } + + // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + props.children = childArray; + } + + return ReactElement(element.type, key, ref, self, source, owner, props); + }; + + /** + * Verifies the object is a ReactElement. + * See https://facebook.github.io/react/docs/top-level-api.html#react.isvalidelement + * @param {?object} object + * @return {boolean} True if `object` is a valid component. + * @final + */ + ReactElement.isValidElement = function (object) { + return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; + }; + + ReactElement.REACT_ELEMENT_TYPE = REACT_ELEMENT_TYPE; + + module.exports = ReactElement; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 10 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactCurrentOwner + */ + + 'use strict'; + + /** + * Keeps track of the current owner. + * + * The current owner is the component who should own any components that are + * currently being constructed. + */ + + var ReactCurrentOwner = { + + /** + * @internal + * @type {ReactComponent} + */ + current: null + + }; + + module.exports = ReactCurrentOwner; + +/***/ }, +/* 11 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + 'use strict'; + + var emptyFunction = __webpack_require__(12); + + /** + * 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 = emptyFunction; + + if (process.env.NODE_ENV !== 'production') { + var printWarning = function printWarning(format) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + var argIndex = 0; + var message = 'Warning: ' + format.replace(/%s/g, function () { + return args[argIndex++]; + }); + 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) {} + }; + + warning = function warning(condition, format) { + if (format === undefined) { + throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); + } + + if (format.indexOf('Failed Composite propType: ') === 0) { + return; // Ignore CompositeComponent proptype check. + } + + if (!condition) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + printWarning.apply(undefined, [format].concat(args)); + } + }; + } + + module.exports = warning; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 12 */ +/***/ function(module, exports) { + + "use strict"; + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + + function makeEmptyFunction(arg) { + return function () { + return arg; + }; + } + + /** + * This function accepts and discards inputs; it has no side effects. This is + * primarily useful idiomatically for overridable function endpoints which + * always need to be callable, since JS lacks a null-call idiom ala Cocoa. + */ + var emptyFunction = function emptyFunction() {}; + + emptyFunction.thatReturns = makeEmptyFunction; + emptyFunction.thatReturnsFalse = makeEmptyFunction(false); + emptyFunction.thatReturnsTrue = makeEmptyFunction(true); + emptyFunction.thatReturnsNull = makeEmptyFunction(null); + emptyFunction.thatReturnsThis = function () { + return this; + }; + emptyFunction.thatReturnsArgument = function (arg) { + return arg; + }; + + module.exports = emptyFunction; + +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule canDefineProperty + */ + + 'use strict'; + + var canDefineProperty = false; + if (process.env.NODE_ENV !== 'production') { + try { + Object.defineProperty({}, 'x', { get: function () {} }); + canDefineProperty = true; + } catch (x) { + // IE will fail on defineProperty + } + } + + module.exports = canDefineProperty; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule traverseAllChildren + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var ReactCurrentOwner = __webpack_require__(10); + var ReactElement = __webpack_require__(9); + + var getIteratorFn = __webpack_require__(15); + var invariant = __webpack_require__(8); + var KeyEscapeUtils = __webpack_require__(16); + var warning = __webpack_require__(11); + + var SEPARATOR = '.'; + var SUBSEPARATOR = ':'; + + /** + * TODO: Test that a single child and an array with one item have the same key + * pattern. + */ + + var didWarnAboutMaps = false; + + /** + * Generate a key string that identifies a component within a set. + * + * @param {*} component A component that could contain a manual key. + * @param {number} index Index that is used if a manual key is not provided. + * @return {string} + */ + function getComponentKey(component, index) { + // Do some typechecking here since we call this blindly. We want to ensure + // that we don't block potential future ES APIs. + if (component && typeof component === 'object' && component.key != null) { + // Explicit key + return KeyEscapeUtils.escape(component.key); + } + // Implicit key determined by the index in the set + return index.toString(36); + } + + /** + * @param {?*} children Children tree container. + * @param {!string} nameSoFar Name of the key path so far. + * @param {!function} callback Callback to invoke with each child found. + * @param {?*} traverseContext Used to pass information throughout the traversal + * process. + * @return {!number} The number of children in this subtree. + */ + function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) { + var type = typeof children; + + if (type === 'undefined' || type === 'boolean') { + // All of the above are perceived as null. + children = null; + } + + if (children === null || type === 'string' || type === 'number' || ReactElement.isValidElement(children)) { + callback(traverseContext, children, + // If it's the only child, treat the name as if it was wrapped in an array + // so that it's consistent if the number of children grows. + nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar); + return 1; + } + + var child; + var nextName; + var subtreeCount = 0; // Count of children found in the current subtree. + var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; + + if (Array.isArray(children)) { + for (var i = 0; i < children.length; i++) { + child = children[i]; + nextName = nextNamePrefix + getComponentKey(child, i); + subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext); + } + } else { + var iteratorFn = getIteratorFn(children); + if (iteratorFn) { + var iterator = iteratorFn.call(children); + var step; + if (iteratorFn !== children.entries) { + var ii = 0; + while (!(step = iterator.next()).done) { + child = step.value; + nextName = nextNamePrefix + getComponentKey(child, ii++); + subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext); + } + } else { + if (process.env.NODE_ENV !== 'production') { + var mapsAsChildrenAddendum = ''; + if (ReactCurrentOwner.current) { + var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName(); + if (mapsAsChildrenOwnerName) { + mapsAsChildrenAddendum = ' Check the render method of `' + mapsAsChildrenOwnerName + '`.'; + } + } + process.env.NODE_ENV !== 'production' ? warning(didWarnAboutMaps, 'Using Maps as children is not yet fully supported. It is an ' + 'experimental feature that might be removed. Convert it to a ' + 'sequence / iterable of keyed ReactElements instead.%s', mapsAsChildrenAddendum) : void 0; + didWarnAboutMaps = true; + } + // Iterator will provide entry [k,v] tuples rather than values. + while (!(step = iterator.next()).done) { + var entry = step.value; + if (entry) { + child = entry[1]; + nextName = nextNamePrefix + KeyEscapeUtils.escape(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0); + subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext); + } + } + } + } else if (type === 'object') { + var addendum = ''; + if (process.env.NODE_ENV !== 'production') { + addendum = ' If you meant to render a collection of children, use an array ' + 'instead or wrap the object using createFragment(object) from the ' + 'React add-ons.'; + if (children._isReactElement) { + addendum = ' It looks like you\'re using an element created by a different ' + 'version of React. Make sure to use only one copy of React.'; + } + if (ReactCurrentOwner.current) { + var name = ReactCurrentOwner.current.getName(); + if (name) { + addendum += ' Check the render method of `' + name + '`.'; + } + } + } + var childrenString = String(children); + true ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum) : _prodInvariant('31', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum) : void 0; + } + } + + return subtreeCount; + } + + /** + * Traverses children that are typically specified as `props.children`, but + * might also be specified through attributes: + * + * - `traverseAllChildren(this.props.children, ...)` + * - `traverseAllChildren(this.props.leftPanelChildren, ...)` + * + * The `traverseContext` is an optional argument that is passed through the + * entire traversal. It can be used to store accumulations or anything else that + * the callback might find relevant. + * + * @param {?*} children Children tree object. + * @param {!function} callback To invoke upon traversing each child. + * @param {?*} traverseContext Context for traversal. + * @return {!number} The number of children in this subtree. + */ + function traverseAllChildren(children, callback, traverseContext) { + if (children == null) { + return 0; + } + + return traverseAllChildrenImpl(children, '', callback, traverseContext); + } + + module.exports = traverseAllChildren; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 15 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule getIteratorFn + * + */ + + 'use strict'; + + /* global Symbol */ + + var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; + var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. + + /** + * Returns the iterator method function contained on the iterable object. + * + * Be sure to invoke the function with the iterable as context: + * + * var iteratorFn = getIteratorFn(myIterable); + * if (iteratorFn) { + * var iterator = iteratorFn.call(myIterable); + * ... + * } + * + * @param {?object} maybeIterable + * @return {?function} + */ + function getIteratorFn(maybeIterable) { + var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); + if (typeof iteratorFn === 'function') { + return iteratorFn; + } + } + + module.exports = getIteratorFn; + +/***/ }, +/* 16 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule KeyEscapeUtils + * + */ + + 'use strict'; + + /** + * Escape and wrap key so it is safe to use as a reactid + * + * @param {string} key to be escaped. + * @return {string} the escaped key. + */ + + function escape(key) { + var escapeRegex = /[=:]/g; + var escaperLookup = { + '=': '=0', + ':': '=2' + }; + var escapedString = ('' + key).replace(escapeRegex, function (match) { + return escaperLookup[match]; + }); + + return '$' + escapedString; + } + + /** + * Unescape and unwrap key for human-readable display + * + * @param {string} key to unescape. + * @return {string} the unescaped key. + */ + function unescape(key) { + var unescapeRegex = /(=0|=2)/g; + var unescaperLookup = { + '=0': '=', + '=2': ':' + }; + var keySubstring = key[0] === '.' && key[1] === '$' ? key.substring(2) : key.substring(1); + + return ('' + keySubstring).replace(unescapeRegex, function (match) { + return unescaperLookup[match]; + }); + } + + var KeyEscapeUtils = { + escape: escape, + unescape: unescape + }; + + module.exports = KeyEscapeUtils; + +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponent + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var ReactNoopUpdateQueue = __webpack_require__(18); + + var canDefineProperty = __webpack_require__(13); + var emptyObject = __webpack_require__(19); + var invariant = __webpack_require__(8); + var warning = __webpack_require__(11); + + /** + * Base class helpers for the updating state of a component. + */ + function ReactComponent(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + // We initialize the default updater but the real one gets injected by the + // renderer. + this.updater = updater || ReactNoopUpdateQueue; + } + + ReactComponent.prototype.isReactComponent = {}; + + /** + * Sets a subset of the state. Always use this to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * + * When a function is provided to setState, it will be called at some point in + * the future (not synchronously). It will be called with the up to date + * component arguments (state, props, context). These values can be different + * from this.* because your function may be called after receiveProps but before + * shouldComponentUpdate, and this new state, props, and context will not yet be + * assigned to this. + * + * @param {object|function} partialState Next partial state or function to + * produce next partial state to be merged with current state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ + ReactComponent.prototype.setState = function (partialState, callback) { + !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : _prodInvariant('85') : void 0; + this.updater.enqueueSetState(this, partialState); + if (callback) { + this.updater.enqueueCallback(this, callback, 'setState'); + } + }; + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldComponentUpdate`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {?function} callback Called after update is complete. + * @final + * @protected + */ + ReactComponent.prototype.forceUpdate = function (callback) { + this.updater.enqueueForceUpdate(this); + if (callback) { + this.updater.enqueueCallback(this, callback, 'forceUpdate'); + } + }; + + /** + * Deprecated APIs. These APIs used to exist on classic React classes but since + * we would like to deprecate them, we're not going to move them over to this + * modern base class. Instead, we define a getter that warns if it's accessed. + */ + if (process.env.NODE_ENV !== 'production') { + var deprecatedAPIs = { + isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'], + replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).'] + }; + var defineDeprecationWarning = function (methodName, info) { + if (canDefineProperty) { + Object.defineProperty(ReactComponent.prototype, methodName, { + get: function () { + process.env.NODE_ENV !== 'production' ? warning(false, '%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]) : void 0; + return undefined; + } + }); + } + }; + for (var fnName in deprecatedAPIs) { + if (deprecatedAPIs.hasOwnProperty(fnName)) { + defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); + } + } + } + + module.exports = ReactComponent; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 18 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactNoopUpdateQueue + */ + + 'use strict'; + + var warning = __webpack_require__(11); + + function warnNoop(publicInstance, callerName) { + if (process.env.NODE_ENV !== 'production') { + var constructor = publicInstance.constructor; + process.env.NODE_ENV !== 'production' ? warning(false, '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op. Please check the code for the %s component.', callerName, callerName, constructor && (constructor.displayName || constructor.name) || 'ReactClass') : void 0; + } + } + + /** + * This is the abstract API for an update queue. + */ + var ReactNoopUpdateQueue = { + + /** + * Checks whether or not this composite component is mounted. + * @param {ReactClass} publicInstance The instance we want to test. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function (publicInstance) { + return false; + }, + + /** + * Enqueue a callback that will be executed after all the pending updates + * have processed. + * + * @param {ReactClass} publicInstance The instance to use as `this` context. + * @param {?function} callback Called after state is updated. + * @internal + */ + enqueueCallback: function (publicInstance, callback) {}, + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldComponentUpdate`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @internal + */ + enqueueForceUpdate: function (publicInstance) { + warnNoop(publicInstance, 'forceUpdate'); + }, + + /** + * Replaces all of the state. Always use this or `setState` to mutate state. + * You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} completeState Next state. + * @internal + */ + enqueueReplaceState: function (publicInstance, completeState) { + warnNoop(publicInstance, 'replaceState'); + }, + + /** + * Sets a subset of the state. This only exists because _pendingState is + * internal. This provides a merging strategy that is not available to deep + * properties which is confusing. TODO: Expose pendingState or don't use it + * during the merge. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} partialState Next partial state to be merged with state. + * @internal + */ + enqueueSetState: function (publicInstance, partialState) { + warnNoop(publicInstance, 'setState'); + } + }; + + module.exports = ReactNoopUpdateQueue; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + 'use strict'; + + var emptyObject = {}; + + if (process.env.NODE_ENV !== 'production') { + Object.freeze(emptyObject); + } + + module.exports = emptyObject; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPureComponent + */ + + 'use strict'; + + var _assign = __webpack_require__(4); + + var ReactComponent = __webpack_require__(17); + var ReactNoopUpdateQueue = __webpack_require__(18); + + var emptyObject = __webpack_require__(19); + + /** + * Base class helpers for the updating state of a component. + */ + function ReactPureComponent(props, context, updater) { + // Duplicated from ReactComponent. + this.props = props; + this.context = context; + this.refs = emptyObject; + // We initialize the default updater but the real one gets injected by the + // renderer. + this.updater = updater || ReactNoopUpdateQueue; + } + + function ComponentDummy() {} + ComponentDummy.prototype = ReactComponent.prototype; + ReactPureComponent.prototype = new ComponentDummy(); + ReactPureComponent.prototype.constructor = ReactPureComponent; + // Avoid an extra prototype jump for these methods. + _assign(ReactPureComponent.prototype, ReactComponent.prototype); + ReactPureComponent.prototype.isPureReactComponent = true; + + module.exports = ReactPureComponent; + +/***/ }, +/* 21 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactClass + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7), + _assign = __webpack_require__(4); + + var ReactComponent = __webpack_require__(17); + var ReactElement = __webpack_require__(9); + var ReactPropTypeLocations = __webpack_require__(22); + var ReactPropTypeLocationNames = __webpack_require__(24); + var ReactNoopUpdateQueue = __webpack_require__(18); + + var emptyObject = __webpack_require__(19); + var invariant = __webpack_require__(8); + var keyMirror = __webpack_require__(23); + var keyOf = __webpack_require__(25); + var warning = __webpack_require__(11); + + var MIXINS_KEY = keyOf({ mixins: null }); + + /** + * Policies that describe methods in `ReactClassInterface`. + */ + var SpecPolicy = keyMirror({ + /** + * These methods may be defined only once by the class specification or mixin. + */ + DEFINE_ONCE: null, + /** + * These methods may be defined by both the class specification and mixins. + * Subsequent definitions will be chained. These methods must return void. + */ + DEFINE_MANY: null, + /** + * These methods are overriding the base class. + */ + OVERRIDE_BASE: null, + /** + * These methods are similar to DEFINE_MANY, except we assume they return + * objects. We try to merge the keys of the return values of all the mixed in + * functions. If there is a key conflict we throw. + */ + DEFINE_MANY_MERGED: null + }); + + var injectedMixins = []; + + /** + * Composite components are higher-level components that compose other composite + * or host components. + * + * To create a new type of `ReactClass`, pass a specification of + * your new class to `React.createClass`. The only requirement of your class + * specification is that you implement a `render` method. + * + * var MyComponent = React.createClass({ + * render: function() { + * return
Hello World
; + * } + * }); + * + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactClassInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will be available on the prototype. + * + * @interface ReactClassInterface + * @internal + */ + var ReactClassInterface = { + + /** + * An array of Mixin objects to include when defining your component. + * + * @type {array} + * @optional + */ + mixins: SpecPolicy.DEFINE_MANY, + + /** + * An object containing properties and methods that should be defined on + * the component's constructor instead of its prototype (static methods). + * + * @type {object} + * @optional + */ + statics: SpecPolicy.DEFINE_MANY, + + /** + * Definition of prop types for this component. + * + * @type {object} + * @optional + */ + propTypes: SpecPolicy.DEFINE_MANY, + + /** + * Definition of context types for this component. + * + * @type {object} + * @optional + */ + contextTypes: SpecPolicy.DEFINE_MANY, + + /** + * Definition of context types this component sets for its children. + * + * @type {object} + * @optional + */ + childContextTypes: SpecPolicy.DEFINE_MANY, + + // ==== Definition methods ==== + + /** + * Invoked when the component is mounted. Values in the mapping will be set on + * `this.props` if that prop is not specified (i.e. using an `in` check). + * + * This method is invoked before `getInitialState` and therefore cannot rely + * on `this.state` or use `this.setState`. + * + * @return {object} + * @optional + */ + getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. + * + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional + */ + getInitialState: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * @return {object} + * @optional + */ + getChildContext: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. + * + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @nosideeffects + * @required + */ + render: SpecPolicy.DEFINE_ONCE, + + // ==== Delegate methods ==== + + /** + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. + * + * @optional + */ + componentWillMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. + * + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked before the component receives new props. + * + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps, nextContext) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional + */ + componentWillReceiveProps: SpecPolicy.DEFINE_MANY, + + /** + * Invoked while deciding if the component should be updated as a result of + * receiving new props, state and/or context. + * + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props/state/context will not require a component + * update. + * + * shouldComponentUpdate: function(nextProps, nextState, nextContext) { + * return !equal(nextProps, this.props) || + * !equal(nextState, this.state) || + * !equal(nextContext, this.context); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @return {boolean} True if the component should update. + * @optional + */ + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, + + /** + * Invoked when the component is about to update due to a transition from + * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState` + * and `nextContext`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @param {ReactReconcileTransaction} transaction + * @optional + */ + componentWillUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {?object} prevContext + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: SpecPolicy.DEFINE_MANY, + + // ==== Advanced methods ==== + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: SpecPolicy.OVERRIDE_BASE + + }; + + /** + * Mapping from class specification keys to special processing functions. + * + * Although these are declared like instance properties in the specification + * when defining classes using `React.createClass`, they are actually static + * and are accessible on the constructor instead of the prototype. Despite + * being static, they must be defined outside of the "statics" key under + * which all other static methods are defined. + */ + var RESERVED_SPEC_KEYS = { + displayName: function (Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function (Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + childContextTypes: function (Constructor, childContextTypes) { + if (process.env.NODE_ENV !== 'production') { + validateTypeDef(Constructor, childContextTypes, ReactPropTypeLocations.childContext); + } + Constructor.childContextTypes = _assign({}, Constructor.childContextTypes, childContextTypes); + }, + contextTypes: function (Constructor, contextTypes) { + if (process.env.NODE_ENV !== 'production') { + validateTypeDef(Constructor, contextTypes, ReactPropTypeLocations.context); + } + Constructor.contextTypes = _assign({}, Constructor.contextTypes, contextTypes); + }, + /** + * Special case getDefaultProps which should move into statics but requires + * automatic merging. + */ + getDefaultProps: function (Constructor, getDefaultProps) { + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps = createMergedResultFunction(Constructor.getDefaultProps, getDefaultProps); + } else { + Constructor.getDefaultProps = getDefaultProps; + } + }, + propTypes: function (Constructor, propTypes) { + if (process.env.NODE_ENV !== 'production') { + validateTypeDef(Constructor, propTypes, ReactPropTypeLocations.prop); + } + Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes); + }, + statics: function (Constructor, statics) { + mixStaticSpecIntoComponent(Constructor, statics); + }, + autobind: function () {} }; + + // noop + function validateTypeDef(Constructor, typeDef, location) { + for (var propName in typeDef) { + if (typeDef.hasOwnProperty(propName)) { + // use a warning instead of an invariant so components + // don't show up in prod but only in __DEV__ + process.env.NODE_ENV !== 'production' ? warning(typeof typeDef[propName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', Constructor.displayName || 'ReactClass', ReactPropTypeLocationNames[location], propName) : void 0; + } + } + } + + function validateMethodOverride(isAlreadyDefined, name) { + var specPolicy = ReactClassInterface.hasOwnProperty(name) ? ReactClassInterface[name] : null; + + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactClassMixin.hasOwnProperty(name)) { + !(specPolicy === SpecPolicy.OVERRIDE_BASE) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.', name) : _prodInvariant('73', name) : void 0; + } + + // Disallow defining methods more than once unless explicitly allowed. + if (isAlreadyDefined) { + !(specPolicy === SpecPolicy.DEFINE_MANY || specPolicy === SpecPolicy.DEFINE_MANY_MERGED) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.', name) : _prodInvariant('74', name) : void 0; + } + } + + /** + * Mixin helper which handles policy validation and reserved + * specification keys when building React classes. + */ + function mixSpecIntoComponent(Constructor, spec) { + if (!spec) { + if (process.env.NODE_ENV !== 'production') { + var typeofSpec = typeof spec; + var isMixinValid = typeofSpec === 'object' && spec !== null; + + process.env.NODE_ENV !== 'production' ? warning(isMixinValid, '%s: You\'re attempting to include a mixin that is either null ' + 'or not an object. Check the mixins included by the component, ' + 'as well as any mixins they include themselves. ' + 'Expected object but got %s.', Constructor.displayName || 'ReactClass', spec === null ? null : typeofSpec) : void 0; + } + + return; + } + + !(typeof spec !== 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to use a component class or function as a mixin. Instead, just use a regular object.') : _prodInvariant('75') : void 0; + !!ReactElement.isValidElement(spec) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to use a component as a mixin. Instead, just use a regular object.') : _prodInvariant('76') : void 0; + + var proto = Constructor.prototype; + var autoBindPairs = proto.__reactAutoBindPairs; + + // By handling mixins before any other properties, we ensure the same + // chaining order is applied to methods with DEFINE_MANY policy, whether + // mixins are listed before or after these methods in the spec. + if (spec.hasOwnProperty(MIXINS_KEY)) { + RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); + } + + for (var name in spec) { + if (!spec.hasOwnProperty(name)) { + continue; + } + + if (name === MIXINS_KEY) { + // We have already handled mixins in a special case above. + continue; + } + + var property = spec[name]; + var isAlreadyDefined = proto.hasOwnProperty(name); + validateMethodOverride(isAlreadyDefined, name); + + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else { + // Setup methods on prototype: + // The following member methods should not be automatically bound: + // 1. Expected ReactClass methods (in the "interface"). + // 2. Overridden methods (that were mixed in). + var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); + var isFunction = typeof property === 'function'; + var shouldAutoBind = isFunction && !isReactClassMethod && !isAlreadyDefined && spec.autobind !== false; + + if (shouldAutoBind) { + autoBindPairs.push(name, property); + proto[name] = property; + } else { + if (isAlreadyDefined) { + var specPolicy = ReactClassInterface[name]; + + // These cases should already be caught by validateMethodOverride. + !(isReactClassMethod && (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.', specPolicy, name) : _prodInvariant('77', specPolicy, name) : void 0; + + // For methods which are defined more than once, call the existing + // methods before calling the new property, merging if appropriate. + if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) { + proto[name] = createMergedResultFunction(proto[name], property); + } else if (specPolicy === SpecPolicy.DEFINE_MANY) { + proto[name] = createChainedFunction(proto[name], property); + } + } else { + proto[name] = property; + if (process.env.NODE_ENV !== 'production') { + // Add verbose displayName to the function, which helps when looking + // at profiling tools. + if (typeof property === 'function' && spec.displayName) { + proto[name].displayName = spec.displayName + '_' + name; + } + } + } + } + } + } + } + + function mixStaticSpecIntoComponent(Constructor, statics) { + if (!statics) { + return; + } + for (var name in statics) { + var property = statics[name]; + if (!statics.hasOwnProperty(name)) { + continue; + } + + var isReserved = name in RESERVED_SPEC_KEYS; + !!isReserved ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You are attempting to define a reserved property, `%s`, that shouldn\'t be on the "statics" key. Define it as an instance property instead; it will still be accessible on the constructor.', name) : _prodInvariant('78', name) : void 0; + + var isInherited = name in Constructor; + !!isInherited ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.', name) : _prodInvariant('79', name) : void 0; + Constructor[name] = property; + } + } + + /** + * Merge two objects, but throw if both contain the same key. + * + * @param {object} one The first object, which is mutated. + * @param {object} two The second object + * @return {object} one after it has been mutated to contain everything in two. + */ + function mergeIntoWithNoDuplicateKeys(one, two) { + !(one && two && typeof one === 'object' && typeof two === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.') : _prodInvariant('80') : void 0; + + for (var key in two) { + if (two.hasOwnProperty(key)) { + !(one[key] === undefined) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the same key: `%s`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.', key) : _prodInvariant('81', key) : void 0; + one[key] = two[key]; + } + } + return one; + } + + /** + * Creates a function that invokes two functions and merges their return values. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ + function createMergedResultFunction(one, two) { + return function mergedResult() { + var a = one.apply(this, arguments); + var b = two.apply(this, arguments); + if (a == null) { + return b; + } else if (b == null) { + return a; + } + var c = {}; + mergeIntoWithNoDuplicateKeys(c, a); + mergeIntoWithNoDuplicateKeys(c, b); + return c; + }; + } + + /** + * Creates a function that invokes two functions and ignores their return vales. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ + function createChainedFunction(one, two) { + return function chainedFunction() { + one.apply(this, arguments); + two.apply(this, arguments); + }; + } + + /** + * Binds a method to the component. + * + * @param {object} component Component whose method is going to be bound. + * @param {function} method Method to be bound. + * @return {function} The bound method. + */ + function bindAutoBindMethod(component, method) { + var boundMethod = method.bind(component); + if (process.env.NODE_ENV !== 'production') { + boundMethod.__reactBoundContext = component; + boundMethod.__reactBoundMethod = method; + boundMethod.__reactBoundArguments = null; + var componentName = component.constructor.displayName; + var _bind = boundMethod.bind; + boundMethod.bind = function (newThis) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + // User is trying to bind() an autobound method; we effectively will + // ignore the value of "this" that the user is trying to use, so + // let's warn. + if (newThis !== component && newThis !== null) { + process.env.NODE_ENV !== 'production' ? warning(false, 'bind(): React component methods may only be bound to the ' + 'component instance. See %s', componentName) : void 0; + } else if (!args.length) { + process.env.NODE_ENV !== 'production' ? warning(false, 'bind(): You are binding a component method to the component. ' + 'React does this for you automatically in a high-performance ' + 'way, so you can safely remove this call. See %s', componentName) : void 0; + return boundMethod; + } + var reboundMethod = _bind.apply(boundMethod, arguments); + reboundMethod.__reactBoundContext = component; + reboundMethod.__reactBoundMethod = method; + reboundMethod.__reactBoundArguments = args; + return reboundMethod; + }; + } + return boundMethod; + } + + /** + * Binds all auto-bound methods in a component. + * + * @param {object} component Component whose method is going to be bound. + */ + function bindAutoBindMethods(component) { + var pairs = component.__reactAutoBindPairs; + for (var i = 0; i < pairs.length; i += 2) { + var autoBindKey = pairs[i]; + var method = pairs[i + 1]; + component[autoBindKey] = bindAutoBindMethod(component, method); + } + } + + /** + * Add more to the ReactClass base class. These are all legacy features and + * therefore not already part of the modern ReactComponent. + */ + var ReactClassMixin = { + + /** + * TODO: This will be deprecated because state should always keep a consistent + * type signature and the only use case for this, is to avoid that. + */ + replaceState: function (newState, callback) { + this.updater.enqueueReplaceState(this, newState); + if (callback) { + this.updater.enqueueCallback(this, callback, 'replaceState'); + } + }, + + /** + * Checks whether or not this composite component is mounted. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function () { + return this.updater.isMounted(this); + } + }; + + var ReactClassComponent = function () {}; + _assign(ReactClassComponent.prototype, ReactComponent.prototype, ReactClassMixin); + + /** + * Module for creating composite components. + * + * @class ReactClass + */ + var ReactClass = { + + /** + * Creates a composite component class given a class specification. + * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + createClass: function (spec) { + var Constructor = function (props, context, updater) { + // This constructor gets overridden by mocks. The argument is used + // by mocks to assert on what gets mounted. + + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: https://fb.me/react-legacyfactory') : void 0; + } + + // Wire up auto-binding + if (this.__reactAutoBindPairs.length) { + bindAutoBindMethods(this); + } + + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + + this.state = null; + + // ReactClasses doesn't have constructors. Instead, they use the + // getInitialState and componentWillMount methods for initialization. + + var initialState = this.getInitialState ? this.getInitialState() : null; + if (process.env.NODE_ENV !== 'production') { + // We allow auto-mocks to proceed as if they're returning null. + if (initialState === undefined && this.getInitialState._isMockFunction) { + // This is probably bad practice. Consider warning here and + // deprecating this convenience. + initialState = null; + } + } + !(typeof initialState === 'object' && !Array.isArray(initialState)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.getInitialState(): must return an object or null', Constructor.displayName || 'ReactCompositeComponent') : _prodInvariant('82', Constructor.displayName || 'ReactCompositeComponent') : void 0; + + this.state = initialState; + }; + Constructor.prototype = new ReactClassComponent(); + Constructor.prototype.constructor = Constructor; + Constructor.prototype.__reactAutoBindPairs = []; + + injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor)); + + mixSpecIntoComponent(Constructor, spec); + + // Initialize the defaultProps property after all mixins have been merged. + if (Constructor.getDefaultProps) { + Constructor.defaultProps = Constructor.getDefaultProps(); + } + + if (process.env.NODE_ENV !== 'production') { + // This is a tag to indicate that the use of these method names is ok, + // since it's used with createClass. If it's not, then it's likely a + // mistake so we'll warn you to use the static property, property + // initializer or constructor respectively. + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps.isReactClassApproved = {}; + } + if (Constructor.prototype.getInitialState) { + Constructor.prototype.getInitialState.isReactClassApproved = {}; + } + } + + !Constructor.prototype.render ? process.env.NODE_ENV !== 'production' ? invariant(false, 'createClass(...): Class specification must implement a `render` method.') : _prodInvariant('83') : void 0; + + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(!Constructor.prototype.componentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', spec.displayName || 'A component') : void 0; + process.env.NODE_ENV !== 'production' ? warning(!Constructor.prototype.componentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', spec.displayName || 'A component') : void 0; + } + + // Reduce time spent doing lookups by setting these on the prototype. + for (var methodName in ReactClassInterface) { + if (!Constructor.prototype[methodName]) { + Constructor.prototype[methodName] = null; + } + } + + return Constructor; + }, + + injection: { + injectMixin: function (mixin) { + injectedMixins.push(mixin); + } + } + + }; + + module.exports = ReactClass; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 22 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypeLocations + */ + + 'use strict'; + + var keyMirror = __webpack_require__(23); + + var ReactPropTypeLocations = keyMirror({ + prop: null, + context: null, + childContext: null + }); + + module.exports = ReactPropTypeLocations; + +/***/ }, +/* 23 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @typechecks static-only + */ + + 'use strict'; + + var invariant = __webpack_require__(8); + + /** + * Constructs an enumeration with keys equal to their value. + * + * For example: + * + * var COLORS = keyMirror({blue: null, red: null}); + * var myColor = COLORS.blue; + * var isColorValid = !!COLORS[myColor]; + * + * The last line could not be performed if the values of the generated enum were + * not equal to their keys. + * + * Input: {key1: val1, key2: val2} + * Output: {key1: key1, key2: key2} + * + * @param {object} obj + * @return {object} + */ + var keyMirror = function keyMirror(obj) { + var ret = {}; + var key; + !(obj instanceof Object && !Array.isArray(obj)) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'keyMirror(...): Argument must be an object.') : invariant(false) : void 0; + for (key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + ret[key] = key; + } + return ret; + }; + + module.exports = keyMirror; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 24 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypeLocationNames + */ + + 'use strict'; + + var ReactPropTypeLocationNames = {}; + + if (process.env.NODE_ENV !== 'production') { + ReactPropTypeLocationNames = { + prop: 'prop', + context: 'context', + childContext: 'child context' + }; + } + + module.exports = ReactPropTypeLocationNames; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 25 */ +/***/ function(module, exports) { + + "use strict"; + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + /** + * Allows extraction of a minified key. Let's the build system minify keys + * without losing the ability to dynamically use key strings as values + * themselves. Pass in an object with a single key/val pair and it will return + * you the string key of that single record. Suppose you want to grab the + * value for a key 'className' inside of an object. Key/val minification may + * have aliased that key to be 'xa12'. keyOf({className: null}) will return + * 'xa12' in that case. Resolve keys you want to use once at startup time, then + * reuse those resolutions. + */ + var keyOf = function keyOf(oneKeyObj) { + var key; + for (key in oneKeyObj) { + if (!oneKeyObj.hasOwnProperty(key)) { + continue; + } + return key; + } + return null; + }; + + module.exports = keyOf; + +/***/ }, +/* 26 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMFactories + */ + + 'use strict'; + + var ReactElement = __webpack_require__(9); + + /** + * Create a factory that creates HTML tag elements. + * + * @private + */ + var createDOMFactory = ReactElement.createFactory; + if (process.env.NODE_ENV !== 'production') { + var ReactElementValidator = __webpack_require__(27); + createDOMFactory = ReactElementValidator.createFactory; + } + + /** + * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes. + * This is also accessible via `React.DOM`. + * + * @public + */ + var ReactDOMFactories = { + a: createDOMFactory('a'), + abbr: createDOMFactory('abbr'), + address: createDOMFactory('address'), + area: createDOMFactory('area'), + article: createDOMFactory('article'), + aside: createDOMFactory('aside'), + audio: createDOMFactory('audio'), + b: createDOMFactory('b'), + base: createDOMFactory('base'), + bdi: createDOMFactory('bdi'), + bdo: createDOMFactory('bdo'), + big: createDOMFactory('big'), + blockquote: createDOMFactory('blockquote'), + body: createDOMFactory('body'), + br: createDOMFactory('br'), + button: createDOMFactory('button'), + canvas: createDOMFactory('canvas'), + caption: createDOMFactory('caption'), + cite: createDOMFactory('cite'), + code: createDOMFactory('code'), + col: createDOMFactory('col'), + colgroup: createDOMFactory('colgroup'), + data: createDOMFactory('data'), + datalist: createDOMFactory('datalist'), + dd: createDOMFactory('dd'), + del: createDOMFactory('del'), + details: createDOMFactory('details'), + dfn: createDOMFactory('dfn'), + dialog: createDOMFactory('dialog'), + div: createDOMFactory('div'), + dl: createDOMFactory('dl'), + dt: createDOMFactory('dt'), + em: createDOMFactory('em'), + embed: createDOMFactory('embed'), + fieldset: createDOMFactory('fieldset'), + figcaption: createDOMFactory('figcaption'), + figure: createDOMFactory('figure'), + footer: createDOMFactory('footer'), + form: createDOMFactory('form'), + h1: createDOMFactory('h1'), + h2: createDOMFactory('h2'), + h3: createDOMFactory('h3'), + h4: createDOMFactory('h4'), + h5: createDOMFactory('h5'), + h6: createDOMFactory('h6'), + head: createDOMFactory('head'), + header: createDOMFactory('header'), + hgroup: createDOMFactory('hgroup'), + hr: createDOMFactory('hr'), + html: createDOMFactory('html'), + i: createDOMFactory('i'), + iframe: createDOMFactory('iframe'), + img: createDOMFactory('img'), + input: createDOMFactory('input'), + ins: createDOMFactory('ins'), + kbd: createDOMFactory('kbd'), + keygen: createDOMFactory('keygen'), + label: createDOMFactory('label'), + legend: createDOMFactory('legend'), + li: createDOMFactory('li'), + link: createDOMFactory('link'), + main: createDOMFactory('main'), + map: createDOMFactory('map'), + mark: createDOMFactory('mark'), + menu: createDOMFactory('menu'), + menuitem: createDOMFactory('menuitem'), + meta: createDOMFactory('meta'), + meter: createDOMFactory('meter'), + nav: createDOMFactory('nav'), + noscript: createDOMFactory('noscript'), + object: createDOMFactory('object'), + ol: createDOMFactory('ol'), + optgroup: createDOMFactory('optgroup'), + option: createDOMFactory('option'), + output: createDOMFactory('output'), + p: createDOMFactory('p'), + param: createDOMFactory('param'), + picture: createDOMFactory('picture'), + pre: createDOMFactory('pre'), + progress: createDOMFactory('progress'), + q: createDOMFactory('q'), + rp: createDOMFactory('rp'), + rt: createDOMFactory('rt'), + ruby: createDOMFactory('ruby'), + s: createDOMFactory('s'), + samp: createDOMFactory('samp'), + script: createDOMFactory('script'), + section: createDOMFactory('section'), + select: createDOMFactory('select'), + small: createDOMFactory('small'), + source: createDOMFactory('source'), + span: createDOMFactory('span'), + strong: createDOMFactory('strong'), + style: createDOMFactory('style'), + sub: createDOMFactory('sub'), + summary: createDOMFactory('summary'), + sup: createDOMFactory('sup'), + table: createDOMFactory('table'), + tbody: createDOMFactory('tbody'), + td: createDOMFactory('td'), + textarea: createDOMFactory('textarea'), + tfoot: createDOMFactory('tfoot'), + th: createDOMFactory('th'), + thead: createDOMFactory('thead'), + time: createDOMFactory('time'), + title: createDOMFactory('title'), + tr: createDOMFactory('tr'), + track: createDOMFactory('track'), + u: createDOMFactory('u'), + ul: createDOMFactory('ul'), + 'var': createDOMFactory('var'), + video: createDOMFactory('video'), + wbr: createDOMFactory('wbr'), + + // SVG + circle: createDOMFactory('circle'), + clipPath: createDOMFactory('clipPath'), + defs: createDOMFactory('defs'), + ellipse: createDOMFactory('ellipse'), + g: createDOMFactory('g'), + image: createDOMFactory('image'), + line: createDOMFactory('line'), + linearGradient: createDOMFactory('linearGradient'), + mask: createDOMFactory('mask'), + path: createDOMFactory('path'), + pattern: createDOMFactory('pattern'), + polygon: createDOMFactory('polygon'), + polyline: createDOMFactory('polyline'), + radialGradient: createDOMFactory('radialGradient'), + rect: createDOMFactory('rect'), + stop: createDOMFactory('stop'), + svg: createDOMFactory('svg'), + text: createDOMFactory('text'), + tspan: createDOMFactory('tspan') + }; + + module.exports = ReactDOMFactories; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 27 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactElementValidator + */ + + /** + * ReactElementValidator provides a wrapper around a element factory + * which validates the props passed to the element. This is intended to be + * used only in DEV and could be replaced by a static type checker for languages + * that support it. + */ + + 'use strict'; + + var ReactCurrentOwner = __webpack_require__(10); + var ReactComponentTreeHook = __webpack_require__(28); + var ReactElement = __webpack_require__(9); + var ReactPropTypeLocations = __webpack_require__(22); + + var checkReactTypeSpec = __webpack_require__(29); + + var canDefineProperty = __webpack_require__(13); + var getIteratorFn = __webpack_require__(15); + var warning = __webpack_require__(11); + + function getDeclarationErrorAddendum() { + if (ReactCurrentOwner.current) { + var name = ReactCurrentOwner.current.getName(); + if (name) { + return ' Check the render method of `' + name + '`.'; + } + } + return ''; + } + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + var ownerHasKeyUseWarning = {}; + + function getCurrentComponentErrorInfo(parentType) { + var info = getDeclarationErrorAddendum(); + + if (!info) { + var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name; + if (parentName) { + info = ' Check the top-level render call using <' + parentName + '>.'; + } + } + return info; + } + + /** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. Error statuses are cached so a warning + * will only be shown once. + * + * @internal + * @param {ReactElement} element Element that requires a key. + * @param {*} parentType element's parent's type. + */ + function validateExplicitKey(element, parentType) { + if (!element._store || element._store.validated || element.key != null) { + return; + } + element._store.validated = true; + + var memoizer = ownerHasKeyUseWarning.uniqueKey || (ownerHasKeyUseWarning.uniqueKey = {}); + + var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); + if (memoizer[currentComponentErrorInfo]) { + return; + } + memoizer[currentComponentErrorInfo] = true; + + // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. + var childOwner = ''; + if (element && element._owner && element._owner !== ReactCurrentOwner.current) { + // Give the component that originally created this child. + childOwner = ' It was passed a child from ' + element._owner.getName() + '.'; + } + + process.env.NODE_ENV !== 'production' ? warning(false, 'Each child in an array or iterator should have a unique "key" prop.' + '%s%s See https://fb.me/react-warning-keys for more information.%s', currentComponentErrorInfo, childOwner, ReactComponentTreeHook.getCurrentStackAddendum(element)) : void 0; + } + + /** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param {ReactNode} node Statically passed child of any type. + * @param {*} parentType node's parent's type. + */ + function validateChildKeys(node, parentType) { + if (typeof node !== 'object') { + return; + } + if (Array.isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; + if (ReactElement.isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (ReactElement.isValidElement(node)) { + // This element was passed in a valid location. + if (node._store) { + node._store.validated = true; + } + } else if (node) { + var iteratorFn = getIteratorFn(node); + // Entry iterators provide implicit keys. + if (iteratorFn) { + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); + var step; + while (!(step = iterator.next()).done) { + if (ReactElement.isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); + } + } + } + } + } + } + + /** + * Given an element, validate that its props follow the propTypes definition, + * provided by the type. + * + * @param {ReactElement} element + */ + function validatePropTypes(element) { + var componentClass = element.type; + if (typeof componentClass !== 'function') { + return; + } + var name = componentClass.displayName || componentClass.name; + if (componentClass.propTypes) { + checkReactTypeSpec(componentClass.propTypes, element.props, ReactPropTypeLocations.prop, name, element, null); + } + if (typeof componentClass.getDefaultProps === 'function') { + process.env.NODE_ENV !== 'production' ? warning(componentClass.getDefaultProps.isReactClassApproved, 'getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.') : void 0; + } + } + + var ReactElementValidator = { + + createElement: function (type, props, children) { + var validType = typeof type === 'string' || typeof type === 'function'; + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + if (!validType) { + process.env.NODE_ENV !== 'production' ? warning(false, 'React.createElement: type should not be null, undefined, boolean, or ' + 'number. It should be a string (for DOM elements) or a ReactClass ' + '(for composite components).%s', getDeclarationErrorAddendum()) : void 0; + } + + var element = ReactElement.createElement.apply(this, arguments); + + // The result can be nullish if a mock or a custom function is used. + // TODO: Drop this when these are no longer allowed as the type argument. + if (element == null) { + return element; + } + + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing errors. + // We don't want exception behavior to differ between dev and prod. + // (Rendering will throw with a helpful message and as soon as the type is + // fixed, the key warnings will appear.) + if (validType) { + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], type); + } + } + + validatePropTypes(element); + + return element; + }, + + createFactory: function (type) { + var validatedFactory = ReactElementValidator.createElement.bind(null, type); + // Legacy hook TODO: Warn if this is accessed + validatedFactory.type = type; + + if (process.env.NODE_ENV !== 'production') { + if (canDefineProperty) { + Object.defineProperty(validatedFactory, 'type', { + enumerable: false, + get: function () { + process.env.NODE_ENV !== 'production' ? warning(false, 'Factory.type is deprecated. Access the class directly ' + 'before passing it to createFactory.') : void 0; + Object.defineProperty(this, 'type', { + value: type + }); + return type; + } + }); + } + } + + return validatedFactory; + }, + + cloneElement: function (element, props, children) { + var newElement = ReactElement.cloneElement.apply(this, arguments); + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], newElement.type); + } + validatePropTypes(newElement); + return newElement; + } + + }; + + module.exports = ReactElementValidator; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 28 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentTreeHook + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var ReactCurrentOwner = __webpack_require__(10); + + var invariant = __webpack_require__(8); + var warning = __webpack_require__(11); + + function isNative(fn) { + // Based on isNative() from Lodash + var funcToString = Function.prototype.toString; + var hasOwnProperty = Object.prototype.hasOwnProperty; + var reIsNative = RegExp('^' + funcToString + // Take an example native function source for comparison + .call(hasOwnProperty) + // Strip regex characters so we can use it for regex + .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') + // Remove hasOwnProperty from the template to make it generic + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'); + try { + var source = funcToString.call(fn); + return reIsNative.test(source); + } catch (err) { + return false; + } + } + + var canUseCollections = + // Array.from + typeof Array.from === 'function' && + // Map + typeof Map === 'function' && isNative(Map) && + // Map.prototype.keys + Map.prototype != null && typeof Map.prototype.keys === 'function' && isNative(Map.prototype.keys) && + // Set + typeof Set === 'function' && isNative(Set) && + // Set.prototype.keys + Set.prototype != null && typeof Set.prototype.keys === 'function' && isNative(Set.prototype.keys); + + var itemMap; + var rootIDSet; + + var itemByKey; + var rootByKey; + + if (canUseCollections) { + itemMap = new Map(); + rootIDSet = new Set(); + } else { + itemByKey = {}; + rootByKey = {}; + } + + var unmountedIDs = []; + + // Use non-numeric keys to prevent V8 performance issues: + // https://github.com/facebook/react/pull/7232 + function getKeyFromID(id) { + return '.' + id; + } + function getIDFromKey(key) { + return parseInt(key.substr(1), 10); + } + + function get(id) { + if (canUseCollections) { + return itemMap.get(id); + } else { + var key = getKeyFromID(id); + return itemByKey[key]; + } + } + + function remove(id) { + if (canUseCollections) { + itemMap['delete'](id); + } else { + var key = getKeyFromID(id); + delete itemByKey[key]; + } + } + + function create(id, element, parentID) { + var item = { + element: element, + parentID: parentID, + text: null, + childIDs: [], + isMounted: false, + updateCount: 0 + }; + + if (canUseCollections) { + itemMap.set(id, item); + } else { + var key = getKeyFromID(id); + itemByKey[key] = item; + } + } + + function addRoot(id) { + if (canUseCollections) { + rootIDSet.add(id); + } else { + var key = getKeyFromID(id); + rootByKey[key] = true; + } + } + + function removeRoot(id) { + if (canUseCollections) { + rootIDSet['delete'](id); + } else { + var key = getKeyFromID(id); + delete rootByKey[key]; + } + } + + function getRegisteredIDs() { + if (canUseCollections) { + return Array.from(itemMap.keys()); + } else { + return Object.keys(itemByKey).map(getIDFromKey); + } + } + + function getRootIDs() { + if (canUseCollections) { + return Array.from(rootIDSet.keys()); + } else { + return Object.keys(rootByKey).map(getIDFromKey); + } + } + + function purgeDeep(id) { + var item = get(id); + if (item) { + var childIDs = item.childIDs; + + remove(id); + childIDs.forEach(purgeDeep); + } + } + + function describeComponentFrame(name, source, ownerName) { + return '\n in ' + name + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : ''); + } + + function getDisplayName(element) { + if (element == null) { + return '#empty'; + } else if (typeof element === 'string' || typeof element === 'number') { + return '#text'; + } else if (typeof element.type === 'string') { + return element.type; + } else { + return element.type.displayName || element.type.name || 'Unknown'; + } + } + + function describeID(id) { + var name = ReactComponentTreeHook.getDisplayName(id); + var element = ReactComponentTreeHook.getElement(id); + var ownerID = ReactComponentTreeHook.getOwnerID(id); + var ownerName; + if (ownerID) { + ownerName = ReactComponentTreeHook.getDisplayName(ownerID); + } + process.env.NODE_ENV !== 'production' ? warning(element, 'ReactComponentTreeHook: Missing React element for debugID %s when ' + 'building stack', id) : void 0; + return describeComponentFrame(name, element && element._source, ownerName); + } + + var ReactComponentTreeHook = { + onSetChildren: function (id, nextChildIDs) { + var item = get(id); + item.childIDs = nextChildIDs; + + for (var i = 0; i < nextChildIDs.length; i++) { + var nextChildID = nextChildIDs[i]; + var nextChild = get(nextChildID); + !nextChild ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected hook events to fire for the child before its parent includes it in onSetChildren().') : _prodInvariant('140') : void 0; + !(nextChild.childIDs != null || typeof nextChild.element !== 'object' || nextChild.element == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected onSetChildren() to fire for a container child before its parent includes it in onSetChildren().') : _prodInvariant('141') : void 0; + !nextChild.isMounted ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected onMountComponent() to fire for the child before its parent includes it in onSetChildren().') : _prodInvariant('71') : void 0; + if (nextChild.parentID == null) { + nextChild.parentID = id; + // TODO: This shouldn't be necessary but mounting a new root during in + // componentWillMount currently causes not-yet-mounted components to + // be purged from our tree data so their parent ID is missing. + } + !(nextChild.parentID === id) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected onBeforeMountComponent() parent and onSetChildren() to be consistent (%s has parents %s and %s).', nextChildID, nextChild.parentID, id) : _prodInvariant('142', nextChildID, nextChild.parentID, id) : void 0; + } + }, + onBeforeMountComponent: function (id, element, parentID) { + create(id, element, parentID); + }, + onBeforeUpdateComponent: function (id, element) { + var item = get(id); + if (!item || !item.isMounted) { + // We may end up here as a result of setState() in componentWillUnmount(). + // In this case, ignore the element. + return; + } + item.element = element; + }, + onMountComponent: function (id) { + var item = get(id); + item.isMounted = true; + var isRoot = item.parentID === 0; + if (isRoot) { + addRoot(id); + } + }, + onUpdateComponent: function (id) { + var item = get(id); + if (!item || !item.isMounted) { + // We may end up here as a result of setState() in componentWillUnmount(). + // In this case, ignore the element. + return; + } + item.updateCount++; + }, + onUnmountComponent: function (id) { + var item = get(id); + if (item) { + // We need to check if it exists. + // `item` might not exist if it is inside an error boundary, and a sibling + // error boundary child threw while mounting. Then this instance never + // got a chance to mount, but it still gets an unmounting event during + // the error boundary cleanup. + item.isMounted = false; + var isRoot = item.parentID === 0; + if (isRoot) { + removeRoot(id); + } + } + unmountedIDs.push(id); + }, + purgeUnmountedComponents: function () { + if (ReactComponentTreeHook._preventPurging) { + // Should only be used for testing. + return; + } + + for (var i = 0; i < unmountedIDs.length; i++) { + var id = unmountedIDs[i]; + purgeDeep(id); + } + unmountedIDs.length = 0; + }, + isMounted: function (id) { + var item = get(id); + return item ? item.isMounted : false; + }, + getCurrentStackAddendum: function (topElement) { + var info = ''; + if (topElement) { + var type = topElement.type; + var name = typeof type === 'function' ? type.displayName || type.name : type; + var owner = topElement._owner; + info += describeComponentFrame(name || 'Unknown', topElement._source, owner && owner.getName()); + } + + var currentOwner = ReactCurrentOwner.current; + var id = currentOwner && currentOwner._debugID; + + info += ReactComponentTreeHook.getStackAddendumByID(id); + return info; + }, + getStackAddendumByID: function (id) { + var info = ''; + while (id) { + info += describeID(id); + id = ReactComponentTreeHook.getParentID(id); + } + return info; + }, + getChildIDs: function (id) { + var item = get(id); + return item ? item.childIDs : []; + }, + getDisplayName: function (id) { + var element = ReactComponentTreeHook.getElement(id); + if (!element) { + return null; + } + return getDisplayName(element); + }, + getElement: function (id) { + var item = get(id); + return item ? item.element : null; + }, + getOwnerID: function (id) { + var element = ReactComponentTreeHook.getElement(id); + if (!element || !element._owner) { + return null; + } + return element._owner._debugID; + }, + getParentID: function (id) { + var item = get(id); + return item ? item.parentID : null; + }, + getSource: function (id) { + var item = get(id); + var element = item ? item.element : null; + var source = element != null ? element._source : null; + return source; + }, + getText: function (id) { + var element = ReactComponentTreeHook.getElement(id); + if (typeof element === 'string') { + return element; + } else if (typeof element === 'number') { + return '' + element; + } else { + return null; + } + }, + getUpdateCount: function (id) { + var item = get(id); + return item ? item.updateCount : 0; + }, + + + getRegisteredIDs: getRegisteredIDs, + + getRootIDs: getRootIDs + }; + + module.exports = ReactComponentTreeHook; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 29 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule checkReactTypeSpec + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var ReactPropTypeLocationNames = __webpack_require__(24); + var ReactPropTypesSecret = __webpack_require__(30); + + var invariant = __webpack_require__(8); + var warning = __webpack_require__(11); + + var ReactComponentTreeHook; + + if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'test') { + // Temporary hack. + // Inline requires don't work well with Jest: + // https://github.com/facebook/react/issues/7240 + // Remove the inline requires when we don't need them anymore: + // https://github.com/facebook/react/pull/7178 + ReactComponentTreeHook = __webpack_require__(28); + } + + var loggedTypeFailures = {}; + + /** + * 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 {?object} element The React element that is being type-checked + * @param {?number} debugID The React component instance that is being type-checked + * @private + */ + function checkReactTypeSpec(typeSpecs, values, location, componentName, element, debugID) { + for (var typeSpecName in typeSpecs) { + if (typeSpecs.hasOwnProperty(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. + !(typeof typeSpecs[typeSpecName] === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName) : _prodInvariant('84', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName) : void 0; + error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); + } catch (ex) { + error = ex; + } + process.env.NODE_ENV !== 'production' ? warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName, typeof error) : void 0; + 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 componentStackInfo = ''; + + if (process.env.NODE_ENV !== 'production') { + if (!ReactComponentTreeHook) { + ReactComponentTreeHook = __webpack_require__(28); + } + if (debugID !== null) { + componentStackInfo = ReactComponentTreeHook.getStackAddendumByID(debugID); + } else if (element !== null) { + componentStackInfo = ReactComponentTreeHook.getCurrentStackAddendum(element); + } + } + + process.env.NODE_ENV !== 'production' ? warning(false, 'Failed %s type: %s%s', location, error.message, componentStackInfo) : void 0; + } + } + } + } + + module.exports = checkReactTypeSpec; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 30 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypesSecret + */ + + 'use strict'; + + var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; + + module.exports = ReactPropTypesSecret; + +/***/ }, +/* 31 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypes + */ + + 'use strict'; + + var ReactElement = __webpack_require__(9); + var ReactPropTypeLocationNames = __webpack_require__(24); + var ReactPropTypesSecret = __webpack_require__(30); + + var emptyFunction = __webpack_require__(12); + var getIteratorFn = __webpack_require__(15); + var warning = __webpack_require__(11); + + /** + * Collection of methods that allow declaration and validation of props that are + * supplied to React components. Example usage: + * + * var Props = require('ReactPropTypes'); + * var MyArticle = React.createClass({ + * propTypes: { + * // An optional string prop named "description". + * description: Props.string, + * + * // A required enum prop named "category". + * category: Props.oneOf(['News','Photos']).isRequired, + * + * // A prop named "dialog" that requires an instance of Dialog. + * dialog: Props.instanceOf(Dialog).isRequired + * }, + * render: function() { ... } + * }); + * + * A more formal specification of how these methods are used: + * + * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) + * decl := ReactPropTypes.{type}(.isRequired)? + * + * Each and every declaration produces a function with the same signature. This + * allows the creation of custom validation functions. For example: + * + * var MyLink = React.createClass({ + * propTypes: { + * // An optional string or URI prop named "href". + * href: function(props, propName, componentName) { + * var propValue = props[propName]; + * if (propValue != null && typeof propValue !== 'string' && + * !(propValue instanceof URI)) { + * return new Error( + * 'Expected a string or an URI for ' + propName + ' in ' + + * componentName + * ); + * } + * } + * }, + * render: function() {...} + * }); + * + * @internal + */ + + var ANONYMOUS = '<>'; + + var ReactPropTypes = { + array: createPrimitiveTypeChecker('array'), + bool: createPrimitiveTypeChecker('boolean'), + func: createPrimitiveTypeChecker('function'), + number: createPrimitiveTypeChecker('number'), + object: createPrimitiveTypeChecker('object'), + string: createPrimitiveTypeChecker('string'), + symbol: createPrimitiveTypeChecker('symbol'), + + any: createAnyTypeChecker(), + arrayOf: createArrayOfTypeChecker, + element: createElementTypeChecker(), + instanceOf: createInstanceTypeChecker, + node: createNodeChecker(), + objectOf: createObjectOfTypeChecker, + oneOf: createEnumTypeChecker, + oneOfType: createUnionTypeChecker, + shape: createShapeTypeChecker + }; + + /** + * 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 + */ + /*eslint-disable no-self-compare*/ + function is(x, y) { + // SameValue algorithm + if (x === y) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + return x !== 0 || 1 / x === 1 / y; + } else { + // Step 6.a: NaN == NaN + return x !== x && y !== y; + } + } + /*eslint-enable no-self-compare*/ + + /** + * We use an Error-like object for backward compatibility as people may call + * PropTypes directly and inspect their output. However we don't use real + * Errors anymore. We don't inspect their stack anyway, and creating them + * is prohibitively expensive if they are created too often, such as what + * happens in oneOfType() for any type before the one that matched. + */ + function PropTypeError(message) { + this.message = message; + this.stack = ''; + } + // Make `instanceof Error` still work for returned errors. + PropTypeError.prototype = Error.prototype; + + function createChainableTypeChecker(validate) { + if (process.env.NODE_ENV !== 'production') { + var manualPropTypeCallCache = {}; + } + function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { + componentName = componentName || ANONYMOUS; + propFullName = propFullName || propName; + if (process.env.NODE_ENV !== 'production') { + if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') { + var cacheKey = componentName + ':' + propName; + if (!manualPropTypeCallCache[cacheKey]) { + process.env.NODE_ENV !== 'production' ? warning(false, 'You are manually calling a React.PropTypes validation ' + 'function for the `%s` prop on `%s`. This is deprecated ' + 'and will not work in the next major version. You may be ' + 'seeing this warning due to a third-party PropTypes library. ' + 'See https://fb.me/react-warning-dont-call-proptypes for details.', propFullName, componentName) : void 0; + manualPropTypeCallCache[cacheKey] = true; + } + } + } + if (props[propName] == null) { + var locationName = ReactPropTypeLocationNames[location]; + if (isRequired) { + return new PropTypeError('Required ' + locationName + ' `' + propFullName + '` was not specified in ' + ('`' + componentName + '`.')); + } + return null; + } else { + return validate(props, propName, componentName, location, propFullName); + } + } + + var chainedCheckType = checkType.bind(null, false); + chainedCheckType.isRequired = checkType.bind(null, true); + + return chainedCheckType; + } + + function createPrimitiveTypeChecker(expectedType) { + function validate(props, propName, componentName, location, propFullName, secret) { + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== expectedType) { + var locationName = ReactPropTypeLocationNames[location]; + // `propValue` being instance of, say, date/regexp, pass the 'object' + // check, but we can offer a more precise error message here rather than + // 'of type `object`'. + var preciseType = getPreciseType(propValue); + + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); + } + return null; + } + return createChainableTypeChecker(validate); + } + + function createAnyTypeChecker() { + return createChainableTypeChecker(emptyFunction.thatReturns(null)); + } + + function createArrayOfTypeChecker(typeChecker) { + function validate(props, propName, componentName, location, propFullName) { + if (typeof typeChecker !== 'function') { + return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); + } + var propValue = props[propName]; + if (!Array.isArray(propValue)) { + var locationName = ReactPropTypeLocationNames[location]; + var propType = getPropType(propValue); + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); + } + for (var i = 0; i < propValue.length; i++) { + var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret); + if (error instanceof Error) { + return error; + } + } + return null; + } + return createChainableTypeChecker(validate); + } + + function createElementTypeChecker() { + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + if (!ReactElement.isValidElement(propValue)) { + var locationName = ReactPropTypeLocationNames[location]; + var propType = getPropType(propValue); + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); + } + return null; + } + return createChainableTypeChecker(validate); + } + + function createInstanceTypeChecker(expectedClass) { + function validate(props, propName, componentName, location, propFullName) { + if (!(props[propName] instanceof expectedClass)) { + var locationName = ReactPropTypeLocationNames[location]; + var expectedClassName = expectedClass.name || ANONYMOUS; + var actualClassName = getClassName(props[propName]); + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); + } + return null; + } + return createChainableTypeChecker(validate); + } + + function createEnumTypeChecker(expectedValues) { + if (!Array.isArray(expectedValues)) { + process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0; + return emptyFunction.thatReturnsNull; + } + + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + for (var i = 0; i < expectedValues.length; i++) { + if (is(propValue, expectedValues[i])) { + return null; + } + } + + var locationName = ReactPropTypeLocationNames[location]; + var valuesString = JSON.stringify(expectedValues); + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); + } + return createChainableTypeChecker(validate); + } + + function createObjectOfTypeChecker(typeChecker) { + function validate(props, propName, componentName, location, propFullName) { + if (typeof typeChecker !== 'function') { + return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); + } + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== 'object') { + var locationName = ReactPropTypeLocationNames[location]; + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); + } + for (var key in propValue) { + if (propValue.hasOwnProperty(key)) { + var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); + if (error instanceof Error) { + return error; + } + } + } + return null; + } + return createChainableTypeChecker(validate); + } + + function createUnionTypeChecker(arrayOfTypeCheckers) { + if (!Array.isArray(arrayOfTypeCheckers)) { + process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0; + return emptyFunction.thatReturnsNull; + } + + function validate(props, propName, componentName, location, propFullName) { + for (var i = 0; i < arrayOfTypeCheckers.length; i++) { + var checker = arrayOfTypeCheckers[i]; + if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) { + return null; + } + } + + var locationName = ReactPropTypeLocationNames[location]; + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); + } + return createChainableTypeChecker(validate); + } + + function createNodeChecker() { + function validate(props, propName, componentName, location, propFullName) { + if (!isNode(props[propName])) { + var locationName = ReactPropTypeLocationNames[location]; + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); + } + return null; + } + return createChainableTypeChecker(validate); + } + + function createShapeTypeChecker(shapeTypes) { + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== 'object') { + var locationName = ReactPropTypeLocationNames[location]; + return new PropTypeError('Invalid ' + locationName + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); + } + for (var key in shapeTypes) { + var checker = shapeTypes[key]; + if (!checker) { + continue; + } + var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); + if (error) { + return error; + } + } + return null; + } + return createChainableTypeChecker(validate); + } + + function isNode(propValue) { + switch (typeof propValue) { + case 'number': + case 'string': + case 'undefined': + return true; + case 'boolean': + return !propValue; + case 'object': + if (Array.isArray(propValue)) { + return propValue.every(isNode); + } + if (propValue === null || ReactElement.isValidElement(propValue)) { + return true; + } + + var iteratorFn = getIteratorFn(propValue); + if (iteratorFn) { + var iterator = iteratorFn.call(propValue); + var step; + if (iteratorFn !== propValue.entries) { + while (!(step = iterator.next()).done) { + if (!isNode(step.value)) { + return false; + } + } + } else { + // Iterator will provide entry [k,v] tuples rather than values. + while (!(step = iterator.next()).done) { + var entry = step.value; + if (entry) { + if (!isNode(entry[1])) { + return false; + } + } + } + } + } else { + return false; + } + + return true; + default: + return false; + } + } + + function isSymbol(propType, propValue) { + // Native Symbol. + if (propType === 'symbol') { + return true; + } + + // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' + if (propValue['@@toStringTag'] === 'Symbol') { + return true; + } + + // Fallback for non-spec compliant Symbols which are polyfilled. + if (typeof Symbol === 'function' && propValue instanceof Symbol) { + return true; + } + + return false; + } + + // Equivalent of `typeof` but with special handling for array and regexp. + function getPropType(propValue) { + var propType = typeof propValue; + if (Array.isArray(propValue)) { + return 'array'; + } + if (propValue instanceof RegExp) { + // Old webkits (at least until Android 4.0) return 'function' rather than + // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ + // passes PropTypes.object. + return 'object'; + } + if (isSymbol(propType, propValue)) { + return 'symbol'; + } + return propType; + } + + // This handles more types than `getPropType`. Only used for error messages. + // See `createPrimitiveTypeChecker`. + function getPreciseType(propValue) { + var propType = getPropType(propValue); + if (propType === 'object') { + if (propValue instanceof Date) { + return 'date'; + } else if (propValue instanceof RegExp) { + return 'regexp'; + } + } + return propType; + } + + // Returns class name of the object, if any. + function getClassName(propValue) { + if (!propValue.constructor || !propValue.constructor.name) { + return ANONYMOUS; + } + return propValue.constructor.name; + } + + module.exports = ReactPropTypes; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 32 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactVersion + */ + + 'use strict'; + + module.exports = '15.3.2'; + +/***/ }, +/* 33 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule onlyChild + */ + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var ReactElement = __webpack_require__(9); + + var invariant = __webpack_require__(8); + + /** + * Returns the first child in a collection of children and verifies that there + * is only one child in the collection. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.only + * + * The current implementation of this function assumes that a single child gets + * passed without a wrapper, but the purpose of this helper function is to + * abstract away the particular structure of children. + * + * @param {?object} children Child collection structure. + * @return {ReactElement} The first and only `ReactElement` contained in the + * structure. + */ + function onlyChild(children) { + !ReactElement.isValidElement(children) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'React.Children.only expected to receive a single React element child.') : _prodInvariant('143') : void 0; + return children; + } + + module.exports = onlyChild; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 34 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + module.exports = __webpack_require__(35); + + +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOM + */ + + /* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/ + + 'use strict'; + + var ReactDOMComponentTree = __webpack_require__(36); + var ReactDefaultInjection = __webpack_require__(39); + var ReactMount = __webpack_require__(162); + var ReactReconciler = __webpack_require__(59); + var ReactUpdates = __webpack_require__(56); + var ReactVersion = __webpack_require__(32); + + var findDOMNode = __webpack_require__(167); + var getHostComponentFromComposite = __webpack_require__(168); + var renderSubtreeIntoContainer = __webpack_require__(169); + var warning = __webpack_require__(11); + + ReactDefaultInjection.inject(); + + var ReactDOM = { + findDOMNode: findDOMNode, + render: ReactMount.render, + unmountComponentAtNode: ReactMount.unmountComponentAtNode, + version: ReactVersion, + + /* eslint-disable camelcase */ + unstable_batchedUpdates: ReactUpdates.batchedUpdates, + unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer + }; + + // Inject the runtime into a devtools global hook regardless of browser. + // Allows for debugging when the hook is injected on the page. + /* eslint-enable camelcase */ + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') { + __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ + ComponentTree: { + getClosestInstanceFromNode: ReactDOMComponentTree.getClosestInstanceFromNode, + getNodeFromInstance: function (inst) { + // inst is an internal instance (but could be a composite) + if (inst._renderedComponent) { + inst = getHostComponentFromComposite(inst); + } + if (inst) { + return ReactDOMComponentTree.getNodeFromInstance(inst); + } else { + return null; + } + } + }, + Mount: ReactMount, + Reconciler: ReactReconciler + }); + } + + if (process.env.NODE_ENV !== 'production') { + var ExecutionEnvironment = __webpack_require__(49); + if (ExecutionEnvironment.canUseDOM && window.top === window.self) { + + // First check if devtools is not installed + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { + // If we're in Chrome or Firefox, provide a download link if not installed. + if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) { + // Firefox does not have the issue with devtools loaded over file:// + var showFileUrlMessage = window.location.protocol.indexOf('http') === -1 && navigator.userAgent.indexOf('Firefox') === -1; + console.debug('Download the React DevTools ' + (showFileUrlMessage ? 'and use an HTTP server (instead of a file: URL) ' : '') + 'for a better development experience: ' + 'https://fb.me/react-devtools'); + } + } + + var testFunc = function testFn() {}; + process.env.NODE_ENV !== 'production' ? warning((testFunc.name || testFunc.toString()).indexOf('testFn') !== -1, 'It looks like you\'re using a minified copy of the development build ' + 'of React. When deploying React apps to production, make sure to use ' + 'the production build which skips development warnings and is faster. ' + 'See https://fb.me/react-minification for more details.') : void 0; + + // If we're in IE8, check to see if we are in compatibility mode and provide + // information on preventing compatibility mode + var ieCompatibilityMode = document.documentMode && document.documentMode < 8; + + process.env.NODE_ENV !== 'production' ? warning(!ieCompatibilityMode, 'Internet Explorer is running in compatibility mode; please add the ' + 'following tag to your HTML to prevent this from happening: ' + '') : void 0; + + var expectedFeatures = [ + // shims + Array.isArray, Array.prototype.every, Array.prototype.forEach, Array.prototype.indexOf, Array.prototype.map, Date.now, Function.prototype.bind, Object.keys, String.prototype.split, String.prototype.trim]; + + for (var i = 0; i < expectedFeatures.length; i++) { + if (!expectedFeatures[i]) { + process.env.NODE_ENV !== 'production' ? warning(false, 'One or more ES5 shims expected by React are not available: ' + 'https://fb.me/react-warning-polyfills') : void 0; + break; + } + } + } + } + + if (process.env.NODE_ENV !== 'production') { + var ReactInstrumentation = __webpack_require__(62); + var ReactDOMUnknownPropertyHook = __webpack_require__(170); + var ReactDOMNullInputValuePropHook = __webpack_require__(171); + + ReactInstrumentation.debugTool.addHook(ReactDOMUnknownPropertyHook); + ReactInstrumentation.debugTool.addHook(ReactDOMNullInputValuePropHook); + } + + module.exports = ReactDOM; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 36 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMComponentTree + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var DOMProperty = __webpack_require__(37); + var ReactDOMComponentFlags = __webpack_require__(38); + + var invariant = __webpack_require__(8); + + var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; + var Flags = ReactDOMComponentFlags; + + var internalInstanceKey = '__reactInternalInstance$' + Math.random().toString(36).slice(2); + + /** + * Drill down (through composites and empty components) until we get a host or + * host text component. + * + * This is pretty polymorphic but unavoidable with the current structure we have + * for `_renderedChildren`. + */ + function getRenderedHostOrTextFromComponent(component) { + var rendered; + while (rendered = component._renderedComponent) { + component = rendered; + } + return component; + } + + /** + * Populate `_hostNode` on the rendered host/text component with the given + * DOM node. The passed `inst` can be a composite. + */ + function precacheNode(inst, node) { + var hostInst = getRenderedHostOrTextFromComponent(inst); + hostInst._hostNode = node; + node[internalInstanceKey] = hostInst; + } + + function uncacheNode(inst) { + var node = inst._hostNode; + if (node) { + delete node[internalInstanceKey]; + inst._hostNode = null; + } + } + + /** + * Populate `_hostNode` on each child of `inst`, assuming that the children + * match up with the DOM (element) children of `node`. + * + * We cache entire levels at once to avoid an n^2 problem where we access the + * children of a node sequentially and have to walk from the start to our target + * node every time. + * + * Since we update `_renderedChildren` and the actual DOM at (slightly) + * different times, we could race here and see a newer `_renderedChildren` than + * the DOM nodes we see. To avoid this, ReactMultiChild calls + * `prepareToManageChildren` before we change `_renderedChildren`, at which + * time the container's child nodes are always cached (until it unmounts). + */ + function precacheChildNodes(inst, node) { + if (inst._flags & Flags.hasCachedChildNodes) { + return; + } + var children = inst._renderedChildren; + var childNode = node.firstChild; + outer: for (var name in children) { + if (!children.hasOwnProperty(name)) { + continue; + } + var childInst = children[name]; + var childID = getRenderedHostOrTextFromComponent(childInst)._domID; + if (childID === 0) { + // We're currently unmounting this child in ReactMultiChild; skip it. + continue; + } + // We assume the child nodes are in the same order as the child instances. + for (; childNode !== null; childNode = childNode.nextSibling) { + if (childNode.nodeType === 1 && childNode.getAttribute(ATTR_NAME) === String(childID) || childNode.nodeType === 8 && childNode.nodeValue === ' react-text: ' + childID + ' ' || childNode.nodeType === 8 && childNode.nodeValue === ' react-empty: ' + childID + ' ') { + precacheNode(childInst, childNode); + continue outer; + } + } + // We reached the end of the DOM children without finding an ID match. + true ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Unable to find element with ID %s.', childID) : _prodInvariant('32', childID) : void 0; + } + inst._flags |= Flags.hasCachedChildNodes; + } + + /** + * Given a DOM node, return the closest ReactDOMComponent or + * ReactDOMTextComponent instance ancestor. + */ + function getClosestInstanceFromNode(node) { + if (node[internalInstanceKey]) { + return node[internalInstanceKey]; + } + + // Walk up the tree until we find an ancestor whose instance we have cached. + var parents = []; + while (!node[internalInstanceKey]) { + parents.push(node); + 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 closest; + var inst; + for (; node && (inst = node[internalInstanceKey]); node = parents.pop()) { + closest = inst; + if (parents.length) { + precacheChildNodes(inst, node); + } + } + + return closest; + } + + /** + * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent + * instance, or null if the node was not rendered by this React. + */ + function getInstanceFromNode(node) { + var inst = getClosestInstanceFromNode(node); + if (inst != null && inst._hostNode === node) { + return inst; + } else { + return null; + } + } + + /** + * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding + * DOM node. + */ + function getNodeFromInstance(inst) { + // Without this first invariant, passing a non-DOM-component triggers the next + // invariant for a missing parent, which is super confusing. + !(inst._hostNode !== undefined) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'getNodeFromInstance: Invalid argument.') : _prodInvariant('33') : void 0; + + if (inst._hostNode) { + return inst._hostNode; + } + + // Walk up the tree until we find an ancestor whose DOM node we have cached. + var parents = []; + while (!inst._hostNode) { + parents.push(inst); + !inst._hostParent ? process.env.NODE_ENV !== 'production' ? invariant(false, 'React DOM tree root should always have a node reference.') : _prodInvariant('34') : void 0; + inst = inst._hostParent; + } + + // Now parents contains each ancestor that does *not* have a cached native + // node, and `inst` is the deepest ancestor that does. + for (; parents.length; inst = parents.pop()) { + precacheChildNodes(inst, inst._hostNode); + } + + return inst._hostNode; + } + + var ReactDOMComponentTree = { + getClosestInstanceFromNode: getClosestInstanceFromNode, + getInstanceFromNode: getInstanceFromNode, + getNodeFromInstance: getNodeFromInstance, + precacheChildNodes: precacheChildNodes, + precacheNode: precacheNode, + uncacheNode: uncacheNode + }; + + module.exports = ReactDOMComponentTree; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 37 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMProperty + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var invariant = __webpack_require__(8); + + function checkMask(value, bitmask) { + return (value & bitmask) === bitmask; + } + + var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_PROPERTY: 0x1, + HAS_BOOLEAN_VALUE: 0x4, + HAS_NUMERIC_VALUE: 0x8, + HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8, + HAS_OVERLOADED_BOOLEAN_VALUE: 0x20, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * isCustomAttribute: function that given an attribute name will return true + * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* + * attributes where it's impossible to enumerate all of the possible + * attribute names, + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMAttributeNamespaces: object mapping React attribute name to the DOM + * attribute namespace URL. (Attribute names not specified use no namespace.) + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function (domPropertyConfig) { + var Injection = DOMPropertyInjection; + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; + + if (domPropertyConfig.isCustomAttribute) { + DOMProperty._isCustomAttributeFunctions.push(domPropertyConfig.isCustomAttribute); + } + + for (var propName in Properties) { + !!DOMProperty.properties.hasOwnProperty(propName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property \'%s\' which has already been injected. You may be accidentally injecting the same DOM property config twice, or you may be injecting two configs that have conflicting property names.', propName) : _prodInvariant('48', propName) : void 0; + + var lowerCased = propName.toLowerCase(); + var propConfig = Properties[propName]; + + var propertyInfo = { + attributeName: lowerCased, + attributeNamespace: null, + propertyName: propName, + mutationMethod: null, + + mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY), + hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE), + hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE), + hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE), + hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE) + }; + !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s', propName) : _prodInvariant('50', propName) : void 0; + + if (process.env.NODE_ENV !== 'production') { + DOMProperty.getPossibleStandardName[lowerCased] = propName; + } + + if (DOMAttributeNames.hasOwnProperty(propName)) { + var attributeName = DOMAttributeNames[propName]; + propertyInfo.attributeName = attributeName; + if (process.env.NODE_ENV !== 'production') { + DOMProperty.getPossibleStandardName[attributeName] = propName; + } + } + + if (DOMAttributeNamespaces.hasOwnProperty(propName)) { + propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName]; + } + + if (DOMPropertyNames.hasOwnProperty(propName)) { + propertyInfo.propertyName = DOMPropertyNames[propName]; + } + + if (DOMMutationMethods.hasOwnProperty(propName)) { + propertyInfo.mutationMethod = DOMMutationMethods[propName]; + } + + DOMProperty.properties[propName] = propertyInfo; + } + } + }; + + /* 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 */ + + /** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ + var DOMProperty = { + + ID_ATTRIBUTE_NAME: 'data-reactid', + ROOT_ATTRIBUTE_NAME: 'data-reactroot', + + ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR, + ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040', + + /** + * Map from property "standard name" to an object with info about how to set + * the property in the DOM. Each object contains: + * + * attributeName: + * Used when rendering markup or with `*Attribute()`. + * attributeNamespace + * propertyName: + * Used on DOM node instances. (This includes properties that mutate due to + * external factors.) + * mutationMethod: + * If non-null, used instead of the property or `setAttribute()` after + * initial render. + * mustUseProperty: + * Whether the property must be accessed and mutated as an object property. + * hasBooleanValue: + * Whether the property should be removed when set to a falsey value. + * hasNumericValue: + * Whether the property must be numeric or parse as a numeric and should be + * removed when set to a falsey value. + * hasPositiveNumericValue: + * Whether the property must be positive numeric or parse as a positive + * numeric and should be removed when set to a falsey value. + * hasOverloadedBooleanValue: + * Whether the property can be used as a flag as well as with a value. + * Removed when strictly equal to false; present without a value when + * strictly equal to true; present with a value otherwise. + */ + properties: {}, + + /** + * Mapping from lowercase property names to the properly cased version, used + * to warn in the case of missing properties. Available only in __DEV__. + * @type {Object} + */ + getPossibleStandardName: process.env.NODE_ENV !== 'production' ? {} : null, + + /** + * All of the isCustomAttribute() functions that have been injected. + */ + _isCustomAttributeFunctions: [], + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: function (attributeName) { + for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) { + var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i]; + if (isCustomAttributeFn(attributeName)) { + return true; + } + } + return false; + }, + + injection: DOMPropertyInjection + }; + + module.exports = DOMProperty; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 38 */ +/***/ function(module, exports) { + + /** + * Copyright 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMComponentFlags + */ + + 'use strict'; + + var ReactDOMComponentFlags = { + hasCachedChildNodes: 1 << 0 + }; + + module.exports = ReactDOMComponentFlags; + +/***/ }, +/* 39 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDefaultInjection + */ + + 'use strict'; + + var BeforeInputEventPlugin = __webpack_require__(40); + var ChangeEventPlugin = __webpack_require__(55); + var DefaultEventPluginOrder = __webpack_require__(73); + var EnterLeaveEventPlugin = __webpack_require__(74); + var HTMLDOMPropertyConfig = __webpack_require__(79); + var ReactComponentBrowserEnvironment = __webpack_require__(80); + var ReactDOMComponent = __webpack_require__(94); + var ReactDOMComponentTree = __webpack_require__(36); + var ReactDOMEmptyComponent = __webpack_require__(133); + var ReactDOMTreeTraversal = __webpack_require__(134); + var ReactDOMTextComponent = __webpack_require__(135); + var ReactDefaultBatchingStrategy = __webpack_require__(136); + var ReactEventListener = __webpack_require__(137); + var ReactInjection = __webpack_require__(140); + var ReactReconcileTransaction = __webpack_require__(141); + var SVGDOMPropertyConfig = __webpack_require__(149); + var SelectEventPlugin = __webpack_require__(150); + var SimpleEventPlugin = __webpack_require__(151); + + var alreadyInjected = false; + + function inject() { + if (alreadyInjected) { + // TODO: This is currently true because these injections are shared between + // the client and the server package. They should be built independently + // and not share any injection state. Then this problem will be solved. + return; + } + alreadyInjected = true; + + ReactInjection.EventEmitter.injectReactEventListener(ReactEventListener); + + /** + * Inject modules for resolving DOM hierarchy and plugin ordering. + */ + ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder); + ReactInjection.EventPluginUtils.injectComponentTree(ReactDOMComponentTree); + ReactInjection.EventPluginUtils.injectTreeTraversal(ReactDOMTreeTraversal); + + /** + * Some important event plugins included by default (without having to require + * them). + */ + ReactInjection.EventPluginHub.injectEventPluginsByName({ + SimpleEventPlugin: SimpleEventPlugin, + EnterLeaveEventPlugin: EnterLeaveEventPlugin, + ChangeEventPlugin: ChangeEventPlugin, + SelectEventPlugin: SelectEventPlugin, + BeforeInputEventPlugin: BeforeInputEventPlugin + }); + + ReactInjection.HostComponent.injectGenericComponentClass(ReactDOMComponent); + + ReactInjection.HostComponent.injectTextComponentClass(ReactDOMTextComponent); + + ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig); + ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig); + + ReactInjection.EmptyComponent.injectEmptyComponentFactory(function (instantiate) { + return new ReactDOMEmptyComponent(instantiate); + }); + + ReactInjection.Updates.injectReconcileTransaction(ReactReconcileTransaction); + ReactInjection.Updates.injectBatchingStrategy(ReactDefaultBatchingStrategy); + + ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment); + } + + module.exports = { + inject: inject + }; + +/***/ }, +/* 40 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule BeforeInputEventPlugin + */ + + 'use strict'; + + var EventConstants = __webpack_require__(41); + var EventPropagators = __webpack_require__(42); + var ExecutionEnvironment = __webpack_require__(49); + var FallbackCompositionState = __webpack_require__(50); + var SyntheticCompositionEvent = __webpack_require__(52); + var SyntheticInputEvent = __webpack_require__(54); + + var keyOf = __webpack_require__(25); + + var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space + var START_KEYCODE = 229; + + var canUseCompositionEvent = ExecutionEnvironment.canUseDOM && 'CompositionEvent' in window; + + var documentMode = null; + if (ExecutionEnvironment.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 = ExecutionEnvironment.canUseDOM && 'TextEvent' in window && !documentMode && !isPresto(); + + // 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 = ExecutionEnvironment.canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); + + /** + * Opera <= 12 includes TextEvent in window, but does not fire + * text input events. Rely on keypress instead. + */ + function isPresto() { + var opera = window.opera; + return typeof opera === 'object' && typeof opera.version === 'function' && parseInt(opera.version(), 10) <= 12; + } + + var SPACEBAR_CODE = 32; + var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); + + var topLevelTypes = EventConstants.topLevelTypes; + + // Events and their corresponding property names. + var eventTypes = { + beforeInput: { + phasedRegistrationNames: { + bubbled: keyOf({ onBeforeInput: null }), + captured: keyOf({ onBeforeInputCapture: null }) + }, + dependencies: [topLevelTypes.topCompositionEnd, topLevelTypes.topKeyPress, topLevelTypes.topTextInput, topLevelTypes.topPaste] + }, + compositionEnd: { + phasedRegistrationNames: { + bubbled: keyOf({ onCompositionEnd: null }), + captured: keyOf({ onCompositionEndCapture: null }) + }, + dependencies: [topLevelTypes.topBlur, topLevelTypes.topCompositionEnd, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown] + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: keyOf({ onCompositionStart: null }), + captured: keyOf({ onCompositionStartCapture: null }) + }, + dependencies: [topLevelTypes.topBlur, topLevelTypes.topCompositionStart, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown] + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: keyOf({ onCompositionUpdate: null }), + captured: keyOf({ onCompositionUpdateCapture: null }) + }, + dependencies: [topLevelTypes.topBlur, topLevelTypes.topCompositionUpdate, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown] + } + }; + + // 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 topLevelTypes.topCompositionStart: + return eventTypes.compositionStart; + case topLevelTypes.topCompositionEnd: + return eventTypes.compositionEnd; + case topLevelTypes.topCompositionUpdate: + 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 === topLevelTypes.topKeyDown && 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 topLevelTypes.topKeyUp: + // Command keys insert or clear IME input. + return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; + case topLevelTypes.topKeyDown: + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return nativeEvent.keyCode !== START_KEYCODE; + case topLevelTypes.topKeyPress: + case topLevelTypes.topMouseDown: + case topLevelTypes.topBlur: + // 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; + } + + // Track the current IME composition fallback object, if any. + var currentComposition = null; + + /** + * @return {?object} A SyntheticCompositionEvent. + */ + function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var eventType; + var fallbackData; + + if (canUseCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!currentComposition) { + if (isFallbackCompositionStart(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionStart; + } + } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; + } + + if (!eventType) { + return null; + } + + if (useFallbackCompositionData) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!currentComposition && eventType === eventTypes.compositionStart) { + currentComposition = FallbackCompositionState.getPooled(nativeEventTarget); + } else if (eventType === eventTypes.compositionEnd) { + if (currentComposition) { + fallbackData = currentComposition.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; + } + } + + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The string corresponding to this `beforeInput` event. + */ + function getNativeBeforeInputChars(topLevelType, nativeEvent) { + switch (topLevelType) { + case topLevelTypes.topCompositionEnd: + return getDataFromCustomEvent(nativeEvent); + case topLevelTypes.topKeyPress: + /** + * 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 topLevelTypes.topTextInput: + // 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 blacklist 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 {string} topLevelType Record from `EventConstants`. + * @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 (currentComposition) { + if (topLevelType === topLevelTypes.topCompositionEnd || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { + var chars = currentComposition.getData(); + FallbackCompositionState.release(currentComposition); + currentComposition = null; + return chars; + } + return null; + } + + switch (topLevelType) { + case topLevelTypes.topPaste: + // If a paste event occurs after a keypress, throw out the input + // chars. Paste events should not lead to BeforeInput events. + return null; + case topLevelTypes.topKeyPress: + /** + * 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 (nativeEvent.which && !isKeypressCommand(nativeEvent)) { + return String.fromCharCode(nativeEvent.which); + } + return null; + case topLevelTypes.topCompositionEnd: + return useFallbackCompositionData ? 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; + + 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; + EventPropagators.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) { + return [extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget), extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget)]; + } + }; + + module.exports = BeforeInputEventPlugin; + +/***/ }, +/* 41 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventConstants + */ + + 'use strict'; + + var keyMirror = __webpack_require__(23); + + var PropagationPhases = keyMirror({ bubbled: null, captured: null }); + + /** + * Types of raw signals from the browser caught at the top level. + */ + var topLevelTypes = keyMirror({ + topAbort: null, + topAnimationEnd: null, + topAnimationIteration: null, + topAnimationStart: null, + topBlur: null, + topCanPlay: null, + topCanPlayThrough: null, + topChange: null, + topClick: null, + topCompositionEnd: null, + topCompositionStart: null, + topCompositionUpdate: null, + topContextMenu: null, + topCopy: null, + topCut: null, + topDoubleClick: null, + topDrag: null, + topDragEnd: null, + topDragEnter: null, + topDragExit: null, + topDragLeave: null, + topDragOver: null, + topDragStart: null, + topDrop: null, + topDurationChange: null, + topEmptied: null, + topEncrypted: null, + topEnded: null, + topError: null, + topFocus: null, + topInput: null, + topInvalid: null, + topKeyDown: null, + topKeyPress: null, + topKeyUp: null, + topLoad: null, + topLoadedData: null, + topLoadedMetadata: null, + topLoadStart: null, + topMouseDown: null, + topMouseMove: null, + topMouseOut: null, + topMouseOver: null, + topMouseUp: null, + topPaste: null, + topPause: null, + topPlay: null, + topPlaying: null, + topProgress: null, + topRateChange: null, + topReset: null, + topScroll: null, + topSeeked: null, + topSeeking: null, + topSelectionChange: null, + topStalled: null, + topSubmit: null, + topSuspend: null, + topTextInput: null, + topTimeUpdate: null, + topTouchCancel: null, + topTouchEnd: null, + topTouchMove: null, + topTouchStart: null, + topTransitionEnd: null, + topVolumeChange: null, + topWaiting: null, + topWheel: null + }); + + var EventConstants = { + topLevelTypes: topLevelTypes, + PropagationPhases: PropagationPhases + }; + + module.exports = EventConstants; + +/***/ }, +/* 42 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPropagators + */ + + 'use strict'; + + var EventConstants = __webpack_require__(41); + var EventPluginHub = __webpack_require__(43); + var EventPluginUtils = __webpack_require__(45); + + var accumulateInto = __webpack_require__(47); + var forEachAccumulated = __webpack_require__(48); + var warning = __webpack_require__(11); + + var PropagationPhases = EventConstants.PropagationPhases; + var getListener = EventPluginHub.getListener; + + /** + * 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); + } + + /** + * 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, upwards, event) { + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(inst, 'Dispatching inst must not be null') : void 0; + } + var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; + 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) { + EventPluginUtils.traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } + } + + /** + * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. + */ + function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? EventPluginUtils.getParentInstance(targetInst) : null; + EventPluginUtils.traverseTwoPhase(parentInst, 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 (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 accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); + } + + function accumulateEnterLeaveDispatches(leave, enter, from, to) { + EventPluginUtils.traverseEnterLeave(from, to, accumulateDispatches, leave, enter); + } + + function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); + } + + /** + * 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 event a + * single one. + * + * @constructor EventPropagators + */ + var EventPropagators = { + accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, + accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget, + accumulateDirectDispatches: accumulateDirectDispatches, + accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches + }; + + module.exports = EventPropagators; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 43 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPluginHub + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var EventPluginRegistry = __webpack_require__(44); + var EventPluginUtils = __webpack_require__(45); + var ReactErrorUtils = __webpack_require__(46); + + var accumulateInto = __webpack_require__(47); + var forEachAccumulated = __webpack_require__(48); + var invariant = __webpack_require__(8); + + /** + * Internal store for event listeners + */ + var listenerBank = {}; + + /** + * 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. + * @param {boolean} simulated If the event is simulated (changes exn behavior) + * @private + */ + var executeDispatchesAndRelease = function (event, simulated) { + if (event) { + EventPluginUtils.executeDispatchesInOrder(event, simulated); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } + }; + var executeDispatchesAndReleaseSimulated = function (e) { + return executeDispatchesAndRelease(e, true); + }; + var executeDispatchesAndReleaseTopLevel = function (e) { + return executeDispatchesAndRelease(e, false); + }; + + var getDictionaryKey = function (inst) { + // Prevents V8 performance issue: + // https://github.com/facebook/react/pull/7232 + return '.' + inst._rootNodeID; + }; + + /** + * 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 + */ + var EventPluginHub = { + + /** + * Methods for injecting dependencies. + */ + injection: { + + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName + + }, + + /** + * Stores `listener` at `listenerBank[registrationName][key]`. Is idempotent. + * + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {function} listener The callback to store. + */ + putListener: function (inst, registrationName, listener) { + !(typeof listener === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected %s listener to be a function, instead got type %s', registrationName, typeof listener) : _prodInvariant('94', registrationName, typeof listener) : void 0; + + var key = getDictionaryKey(inst); + var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[key] = listener; + + var PluginModule = EventPluginRegistry.registrationNameModules[registrationName]; + if (PluginModule && PluginModule.didPutListener) { + PluginModule.didPutListener(inst, registrationName, listener); + } + }, + + /** + * @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. + */ + getListener: function (inst, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + var key = getDictionaryKey(inst); + return bankForRegistrationName && bankForRegistrationName[key]; + }, + + /** + * Deletes a listener from the registration bank. + * + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + */ + deleteListener: function (inst, registrationName) { + var PluginModule = EventPluginRegistry.registrationNameModules[registrationName]; + if (PluginModule && PluginModule.willDeleteListener) { + PluginModule.willDeleteListener(inst, registrationName); + } + + var bankForRegistrationName = listenerBank[registrationName]; + // TODO: This should never be null -- when is it? + if (bankForRegistrationName) { + var key = getDictionaryKey(inst); + delete bankForRegistrationName[key]; + } + }, + + /** + * Deletes all listeners for the DOM element with the supplied ID. + * + * @param {object} inst The instance, which is the source of events. + */ + deleteAllListeners: function (inst) { + var key = getDictionaryKey(inst); + for (var registrationName in listenerBank) { + if (!listenerBank.hasOwnProperty(registrationName)) { + continue; + } + + if (!listenerBank[registrationName][key]) { + continue; + } + + var PluginModule = EventPluginRegistry.registrationNameModules[registrationName]; + if (PluginModule && PluginModule.willDeleteListener) { + PluginModule.willDeleteListener(inst, registrationName); + } + + delete listenerBank[registrationName][key]; + } + }, + + /** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events; + var plugins = EventPluginRegistry.plugins; + 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; + }, + + /** + * Enqueues a synthetic event that should be dispatched when + * `processEventQueue` is invoked. + * + * @param {*} events An accumulation of synthetic events. + * @internal + */ + enqueueEvents: function (events) { + if (events) { + eventQueue = accumulateInto(eventQueue, events); + } + }, + + /** + * Dispatches all synthetic events on the event queue. + * + * @internal + */ + processEventQueue: function (simulated) { + // 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 (simulated) { + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseSimulated); + } else { + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + } + !!eventQueue ? process.env.NODE_ENV !== 'production' ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : _prodInvariant('95') : void 0; + // This would be a good time to rethrow if any of the event handlers threw. + ReactErrorUtils.rethrowCaughtError(); + }, + + /** + * These are needed for tests only. Do not use! + */ + __purge: function () { + listenerBank = {}; + }, + + __getListenerBank: function () { + return listenerBank; + } + + }; + + module.exports = EventPluginHub; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 44 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPluginRegistry + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var invariant = __webpack_require__(8); + + /** + * 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) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : _prodInvariant('96', pluginName) : void 0; + if (EventPluginRegistry.plugins[pluginIndex]) { + continue; + } + !PluginModule.extractEvents ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : _prodInvariant('97', pluginName) : void 0; + EventPluginRegistry.plugins[pluginIndex] = PluginModule; + var publishedEvents = PluginModule.eventTypes; + for (var eventName in publishedEvents) { + !publishEventForPlugin(publishedEvents[eventName], PluginModule, eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : _prodInvariant('98', 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) { + !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : _prodInvariant('99', eventName) : void 0; + EventPluginRegistry.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 and + * can be used with `EventPluginHub.putListener` to register listeners. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ + function publishRegistrationName(registrationName, PluginModule, eventName) { + !!EventPluginRegistry.registrationNameModules[registrationName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : _prodInvariant('100', registrationName) : void 0; + EventPluginRegistry.registrationNameModules[registrationName] = PluginModule; + EventPluginRegistry.registrationNameDependencies[registrationName] = PluginModule.eventTypes[eventName].dependencies; + + if (process.env.NODE_ENV !== 'production') { + var lowerCasedName = registrationName.toLowerCase(); + EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName; + + if (registrationName === 'onDoubleClick') { + EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName; + } + } + } + + /** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + var EventPluginRegistry = { + + /** + * Ordered list of injected plugins. + */ + plugins: [], + + /** + * Mapping from event name to dispatch config + */ + eventNameDispatchConfigs: {}, + + /** + * Mapping from registration name to plugin module + */ + registrationNameModules: {}, + + /** + * Mapping from registration name to event name + */ + registrationNameDependencies: {}, + + /** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in __DEV__. + * @type {Object} + */ + possibleRegistrationNames: process.env.NODE_ENV !== 'production' ? {} : null, + + /** + * 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} + */ + injectEventPluginOrder: function (InjectedEventPluginOrder) { + !!EventPluginOrder ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : _prodInvariant('101') : 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} + */ + injectEventPluginsByName: function (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] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : _prodInvariant('102', pluginName) : void 0; + namesToPlugins[pluginName] = PluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } + }, + + /** + * Looks up the plugin for the supplied event. + * + * @param {object} event A synthetic event. + * @return {?object} The plugin that created the supplied event. + * @internal + */ + getPluginModuleForEvent: function (event) { + var dispatchConfig = event.dispatchConfig; + if (dispatchConfig.registrationName) { + return EventPluginRegistry.registrationNameModules[dispatchConfig.registrationName] || null; + } + for (var phase in dispatchConfig.phasedRegistrationNames) { + if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { + continue; + } + var PluginModule = EventPluginRegistry.registrationNameModules[dispatchConfig.phasedRegistrationNames[phase]]; + if (PluginModule) { + return PluginModule; + } + } + return null; + }, + + /** + * Exposed for unit testing. + * @private + */ + _resetEventPlugins: function () { + EventPluginOrder = null; + for (var pluginName in namesToPlugins) { + if (namesToPlugins.hasOwnProperty(pluginName)) { + delete namesToPlugins[pluginName]; + } + } + EventPluginRegistry.plugins.length = 0; + + var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs; + for (var eventName in eventNameDispatchConfigs) { + if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { + delete eventNameDispatchConfigs[eventName]; + } + } + + var registrationNameModules = EventPluginRegistry.registrationNameModules; + for (var registrationName in registrationNameModules) { + if (registrationNameModules.hasOwnProperty(registrationName)) { + delete registrationNameModules[registrationName]; + } + } + + if (process.env.NODE_ENV !== 'production') { + var possibleRegistrationNames = EventPluginRegistry.possibleRegistrationNames; + for (var lowerCasedName in possibleRegistrationNames) { + if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) { + delete possibleRegistrationNames[lowerCasedName]; + } + } + } + } + + }; + + module.exports = EventPluginRegistry; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 45 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPluginUtils + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var EventConstants = __webpack_require__(41); + var ReactErrorUtils = __webpack_require__(46); + + var invariant = __webpack_require__(8); + var warning = __webpack_require__(11); + + /** + * Injected dependencies: + */ + + /** + * - `ComponentTree`: [required] Module that can convert between React instances + * and actual node references. + */ + var ComponentTree; + var TreeTraversal; + var injection = { + injectComponentTree: function (Injected) { + ComponentTree = Injected; + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(Injected && Injected.getNodeFromInstance && Injected.getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.') : void 0; + } + }, + injectTreeTraversal: function (Injected) { + TreeTraversal = Injected; + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(Injected && Injected.isAncestor && Injected.getLowestCommonAncestor, 'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' + 'module is missing isAncestor or getLowestCommonAncestor.') : void 0; + } + } + }; + + var topLevelTypes = EventConstants.topLevelTypes; + + function isEndish(topLevelType) { + return topLevelType === topLevelTypes.topMouseUp || topLevelType === topLevelTypes.topTouchEnd || topLevelType === topLevelTypes.topTouchCancel; + } + + function isMoveish(topLevelType) { + return topLevelType === topLevelTypes.topMouseMove || topLevelType === topLevelTypes.topTouchMove; + } + function isStartish(topLevelType) { + return topLevelType === topLevelTypes.topMouseDown || topLevelType === topLevelTypes.topTouchStart; + } + + var validateEventDispatches; + if (process.env.NODE_ENV !== 'production') { + 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; + + process.env.NODE_ENV !== 'production' ? warning(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.') : void 0; + }; + } + + /** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {boolean} simulated If the event is simulated (changes exn behavior) + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ + function executeDispatch(event, simulated, listener, inst) { + var type = event.type || 'unknown-event'; + event.currentTarget = EventPluginUtils.getNodeFromInstance(inst); + if (simulated) { + ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event); + } else { + ReactErrorUtils.invokeGuardedCallback(type, listener, event); + } + event.currentTarget = null; + } + + /** + * Standard/simple iteration through an event's collected dispatches. + */ + function executeDispatchesInOrder(event, simulated) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + if (process.env.NODE_ENV !== 'production') { + 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, simulated, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, simulated, dispatchListeners, dispatchInstances); + } + event._dispatchListeners = null; + event._dispatchInstances = null; + } + + /** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ + function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + if (process.env.NODE_ENV !== 'production') { + 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. + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } + return null; + } + + /** + * @see executeDispatchesInOrderStopAtTrueImpl + */ + function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; + } + + /** + * 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. + */ + function executeDirectDispatch(event) { + if (process.env.NODE_ENV !== 'production') { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; + !!Array.isArray(dispatchListener) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : _prodInvariant('103') : void 0; + event.currentTarget = dispatchListener ? EventPluginUtils.getNodeFromInstance(dispatchInstance) : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; + } + + /** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ + function hasDispatches(event) { + return !!event._dispatchListeners; + } + + /** + * General utilities that are useful in creating custom Event Plugins. + */ + var EventPluginUtils = { + isEndish: isEndish, + isMoveish: isMoveish, + isStartish: isStartish, + + executeDirectDispatch: executeDirectDispatch, + executeDispatchesInOrder: executeDispatchesInOrder, + executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, + hasDispatches: hasDispatches, + + getInstanceFromNode: function (node) { + return ComponentTree.getInstanceFromNode(node); + }, + getNodeFromInstance: function (node) { + return ComponentTree.getNodeFromInstance(node); + }, + isAncestor: function (a, b) { + return TreeTraversal.isAncestor(a, b); + }, + getLowestCommonAncestor: function (a, b) { + return TreeTraversal.getLowestCommonAncestor(a, b); + }, + getParentInstance: function (inst) { + return TreeTraversal.getParentInstance(inst); + }, + traverseTwoPhase: function (target, fn, arg) { + return TreeTraversal.traverseTwoPhase(target, fn, arg); + }, + traverseEnterLeave: function (from, to, fn, argFrom, argTo) { + return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo); + }, + + injection: injection + }; + + module.exports = EventPluginUtils; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 46 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactErrorUtils + */ + + 'use strict'; + + var caughtError = null; + + /** + * Call a function while guarding against errors that happens within it. + * + * @param {?String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} a First argument + * @param {*} b Second argument + */ + function invokeGuardedCallback(name, func, a, b) { + try { + return func(a, b); + } catch (x) { + if (caughtError === null) { + caughtError = x; + } + return undefined; + } + } + + var ReactErrorUtils = { + invokeGuardedCallback: invokeGuardedCallback, + + /** + * Invoked by ReactTestUtils.Simulate so that any errors thrown by the event + * handler are sure to be rethrown by rethrowCaughtError. + */ + invokeGuardedCallbackWithCatch: invokeGuardedCallback, + + /** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ + rethrowCaughtError: function () { + if (caughtError) { + var error = caughtError; + caughtError = null; + throw error; + } + } + }; + + if (process.env.NODE_ENV !== 'production') { + /** + * To help development we can get better devtools integration by simulating a + * real browser event. + */ + if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { + var fakeNode = document.createElement('react'); + ReactErrorUtils.invokeGuardedCallback = function (name, func, a, b) { + var boundFunc = func.bind(null, a, b); + var evtType = 'react-' + name; + fakeNode.addEventListener(evtType, boundFunc, false); + var evt = document.createEvent('Event'); + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + fakeNode.removeEventListener(evtType, boundFunc, false); + }; + } + } + + module.exports = ReactErrorUtils; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 47 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule accumulateInto + * + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var invariant = __webpack_require__(8); + + /** + * 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) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : _prodInvariant('30') : 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]; + } + + module.exports = accumulateInto; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 48 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule forEachAccumulated + * + */ + + 'use strict'; + + /** + * @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). + */ + + function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } + } + + module.exports = forEachAccumulated; + +/***/ }, +/* 49 */ +/***/ function(module, exports) { + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + 'use strict'; + + var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + + /** + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. + */ + var ExecutionEnvironment = { + + canUseDOM: canUseDOM, + + canUseWorkers: typeof Worker !== 'undefined', + + canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent), + + canUseViewport: canUseDOM && !!window.screen, + + isInWorker: !canUseDOM // For now, this is true - might change in the future. + + }; + + module.exports = ExecutionEnvironment; + +/***/ }, +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule FallbackCompositionState + */ + + 'use strict'; + + var _assign = __webpack_require__(4); + + var PooledClass = __webpack_require__(6); + + var getTextContentAccessor = __webpack_require__(51); + + /** + * This helper class stores 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. + * + * @param {DOMEventTarget} root + */ + function FallbackCompositionState(root) { + this._root = root; + this._startText = this.getText(); + this._fallbackText = null; + } + + _assign(FallbackCompositionState.prototype, { + destructor: function () { + this._root = null; + this._startText = null; + this._fallbackText = null; + }, + + /** + * Get current text of input. + * + * @return {string} + */ + getText: function () { + if ('value' in this._root) { + return this._root.value; + } + return this._root[getTextContentAccessor()]; + }, + + /** + * Determine the differing substring between the initially stored + * text content and the current content. + * + * @return {string} + */ + getData: function () { + if (this._fallbackText) { + return this._fallbackText; + } + + var start; + var startValue = this._startText; + var startLength = startValue.length; + var end; + var endValue = this.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; + this._fallbackText = endValue.slice(start, sliceTail); + return this._fallbackText; + } + }); + + PooledClass.addPoolingTo(FallbackCompositionState); + + module.exports = FallbackCompositionState; + +/***/ }, +/* 51 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule getTextContentAccessor + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(49); + + var contentKey = null; + + /** + * Gets the key used to access text content on a DOM node. + * + * @return {?string} Key used to access text content. + * @internal + */ + function getTextContentAccessor() { + if (!contentKey && ExecutionEnvironment.canUseDOM) { + // Prefer textContent to innerText because many browsers support both but + // SVG elements don't support innerText even when
does. + contentKey = 'textContent' in document.documentElement ? 'textContent' : 'innerText'; + } + return contentKey; + } + + module.exports = getTextContentAccessor; + +/***/ }, +/* 52 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SyntheticCompositionEvent + */ + + 'use strict'; + + var SyntheticEvent = __webpack_require__(53); + + /** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents + */ + var CompositionEventInterface = { + data: null + }; + + /** + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {string} dispatchMarker Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @extends {SyntheticUIEvent} + */ + function SyntheticCompositionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); + } + + SyntheticEvent.augmentClass(SyntheticCompositionEvent, CompositionEventInterface); + + module.exports = SyntheticCompositionEvent; + +/***/ }, +/* 53 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SyntheticEvent + */ + + 'use strict'; + + var _assign = __webpack_require__(4); + + var PooledClass = __webpack_require__(6); + + var emptyFunction = __webpack_require__(12); + var warning = __webpack_require__(11); + + var didWarnForAddedNewProperty = false; + var isProxySupported = typeof Proxy === 'function'; + + var shouldBeReleasedProperties = ['dispatchConfig', '_targetInst', 'nativeEvent', 'isDefaultPrevented', 'isPropagationStopped', '_dispatchListeners', '_dispatchInstances']; + + /** + * @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: emptyFunction.thatReturnsNull, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null + }; + + /** + * 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) { + if (process.env.NODE_ENV !== 'production') { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + if (process.env.NODE_ENV !== 'production') { + 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 = emptyFunction.thatReturnsTrue; + } else { + this.isDefaultPrevented = emptyFunction.thatReturnsFalse; + } + this.isPropagationStopped = emptyFunction.thatReturnsFalse; + 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') { + // eslint-disable-line valid-typeof + event.returnValue = false; + } + this.isDefaultPrevented = emptyFunction.thatReturnsTrue; + }, + + stopPropagation: function () { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== 'unknown') { + // eslint-disable-line valid-typeof + // 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 = emptyFunction.thatReturnsTrue; + }, + + /** + * 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 = emptyFunction.thatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: emptyFunction.thatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function () { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (process.env.NODE_ENV !== 'production') { + Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); + } else { + this[propName] = null; + } + } + for (var i = 0; i < shouldBeReleasedProperties.length; i++) { + this[shouldBeReleasedProperties[i]] = null; + } + if (process.env.NODE_ENV !== 'production') { + Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); + Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', emptyFunction)); + Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', emptyFunction)); + } + } + + }); + + SyntheticEvent.Interface = EventInterface; + + if (process.env.NODE_ENV !== 'production') { + if (isProxySupported) { + /*eslint-disable no-func-assign */ + SyntheticEvent = new Proxy(SyntheticEvent, { + construct: function (target, args) { + return this.apply(target, Object.create(target.prototype), args); + }, + apply: function (constructor, that, args) { + return new Proxy(constructor.apply(that, args), { + set: function (target, prop, value) { + if (prop !== 'isPersistent' && !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1) { + process.env.NODE_ENV !== 'production' ? warning(didWarnForAddedNewProperty || target.isPersistent(), 'This synthetic event is reused for performance reasons. If you\'re ' + 'seeing this, you\'re adding a new property in the synthetic event object. ' + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.') : void 0; + didWarnForAddedNewProperty = true; + } + target[prop] = value; + return true; + } + }); + } + }); + /*eslint-enable no-func-assign */ + } + } + /** + * Helper to reduce boilerplate when creating subclasses. + * + * @param {function} Class + * @param {?object} Interface + */ + SyntheticEvent.augmentClass = function (Class, Interface) { + var Super = this; + + var E = function () {}; + E.prototype = Super.prototype; + var prototype = new E(); + + _assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = _assign({}, Super.Interface, Interface); + Class.augmentClass = Super.augmentClass; + + PooledClass.addPoolingTo(Class, PooledClass.fourArgumentPooler); + }; + + PooledClass.addPoolingTo(SyntheticEvent, PooledClass.fourArgumentPooler); + + module.exports = SyntheticEvent; + + /** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {object} SyntheticEvent + * @param {String} propName + * @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; + process.env.NODE_ENV !== 'production' ? warning(warningCondition, '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; + } + } + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 54 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SyntheticInputEvent + */ + + 'use strict'; + + var SyntheticEvent = __webpack_require__(53); + + /** + * @interface Event + * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 + * /#events-inputevents + */ + var InputEventInterface = { + data: null + }; + + /** + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {string} dispatchMarker Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @extends {SyntheticUIEvent} + */ + function SyntheticInputEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); + } + + SyntheticEvent.augmentClass(SyntheticInputEvent, InputEventInterface); + + module.exports = SyntheticInputEvent; + +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ChangeEventPlugin + */ + + 'use strict'; + + var EventConstants = __webpack_require__(41); + var EventPluginHub = __webpack_require__(43); + var EventPropagators = __webpack_require__(42); + var ExecutionEnvironment = __webpack_require__(49); + var ReactDOMComponentTree = __webpack_require__(36); + var ReactUpdates = __webpack_require__(56); + var SyntheticEvent = __webpack_require__(53); + + var getEventTarget = __webpack_require__(70); + var isEventSupported = __webpack_require__(71); + var isTextInputElement = __webpack_require__(72); + var keyOf = __webpack_require__(25); + + var topLevelTypes = EventConstants.topLevelTypes; + + var eventTypes = { + change: { + phasedRegistrationNames: { + bubbled: keyOf({ onChange: null }), + captured: keyOf({ onChangeCapture: null }) + }, + dependencies: [topLevelTypes.topBlur, topLevelTypes.topChange, topLevelTypes.topClick, topLevelTypes.topFocus, topLevelTypes.topInput, topLevelTypes.topKeyDown, topLevelTypes.topKeyUp, topLevelTypes.topSelectionChange] + } + }; + + /** + * For IE shims + */ + var activeElement = null; + var activeElementInst = null; + var activeElementValue = null; + var activeElementValueProp = null; + + /** + * SECTION: handle `change` event + */ + function shouldUseChangeEvent(elem) { + var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); + return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; + } + + var doesChangeEventBubble = false; + if (ExecutionEnvironment.canUseDOM) { + // See `handleChange` comment below + doesChangeEventBubble = isEventSupported('change') && (!document.documentMode || document.documentMode > 8); + } + + function manualDispatchChangeEvent(nativeEvent) { + var event = SyntheticEvent.getPooled(eventTypes.change, activeElementInst, nativeEvent, getEventTarget(nativeEvent)); + EventPropagators.accumulateTwoPhaseDispatches(event); + + // 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. + ReactUpdates.batchedUpdates(runEventInBatch, event); + } + + function runEventInBatch(event) { + EventPluginHub.enqueueEvents(event); + EventPluginHub.processEventQueue(false); + } + + function startWatchingForChangeEventIE8(target, targetInst) { + activeElement = target; + activeElementInst = targetInst; + activeElement.attachEvent('onchange', manualDispatchChangeEvent); + } + + function stopWatchingForChangeEventIE8() { + if (!activeElement) { + return; + } + activeElement.detachEvent('onchange', manualDispatchChangeEvent); + activeElement = null; + activeElementInst = null; + } + + function getTargetInstForChangeEvent(topLevelType, targetInst) { + if (topLevelType === topLevelTypes.topChange) { + return targetInst; + } + } + function handleEventsForChangeEventIE8(topLevelType, target, targetInst) { + if (topLevelType === topLevelTypes.topFocus) { + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForChangeEventIE8(); + startWatchingForChangeEventIE8(target, targetInst); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForChangeEventIE8(); + } + } + + /** + * SECTION: handle `input` event + */ + var isInputEventSupported = false; + if (ExecutionEnvironment.canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events. + // IE10+ fire input events to often, such when a placeholder + // changes or when an input with a placeholder is focused. + isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 11); + } + + /** + * (For IE <=11) Replacement getter/setter for the `value` property that gets + * set on the active element. + */ + var newValueProp = { + get: function () { + return activeElementValueProp.get.call(this); + }, + set: function (val) { + // Cast to a string so we can do equality checks. + activeElementValue = '' + val; + activeElementValueProp.set.call(this, val); + } + }; + + /** + * (For IE <=11) 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; + activeElementValue = target.value; + activeElementValueProp = Object.getOwnPropertyDescriptor(target.constructor.prototype, 'value'); + + // Not guarded in a canDefineProperty check: IE8 supports defineProperty only + // on DOM elements + Object.defineProperty(activeElement, 'value', newValueProp); + if (activeElement.attachEvent) { + activeElement.attachEvent('onpropertychange', handlePropertyChange); + } else { + activeElement.addEventListener('propertychange', handlePropertyChange, false); + } + } + + /** + * (For IE <=11) Removes the event listeners from the currently-tracked element, + * if any exists. + */ + function stopWatchingForValueChange() { + if (!activeElement) { + return; + } + + // delete restores the original property definition + delete activeElement.value; + + if (activeElement.detachEvent) { + activeElement.detachEvent('onpropertychange', handlePropertyChange); + } else { + activeElement.removeEventListener('propertychange', handlePropertyChange, false); + } + + activeElement = null; + activeElementInst = null; + activeElementValue = null; + activeElementValueProp = null; + } + + /** + * (For IE <=11) 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; + } + var value = nativeEvent.srcElement.value; + if (value === activeElementValue) { + return; + } + activeElementValue = value; + + manualDispatchChangeEvent(nativeEvent); + } + + /** + * If a `change` event should be fired, returns the target's ID. + */ + function getTargetInstForInputEvent(topLevelType, targetInst) { + if (topLevelType === topLevelTypes.topInput) { + // In modern browsers (i.e., not IE8 or IE9), the input event is exactly + // what we want so fall through here and trigger an abstract event + return targetInst; + } + } + + function handleEventsForInputEventIE(topLevelType, target, targetInst) { + if (topLevelType === topLevelTypes.topFocus) { + // In IE8, we can capture almost all .value changes by adding a + // propertychange handler and looking for events with propertyName + // equal to 'value' + // In IE9-11, 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 === topLevelTypes.topBlur) { + stopWatchingForValueChange(); + } + } + + // For IE8 and IE9. + function getTargetInstForInputEventIE(topLevelType, targetInst) { + if (topLevelType === topLevelTypes.topSelectionChange || topLevelType === topLevelTypes.topKeyUp || topLevelType === topLevelTypes.topKeyDown) { + // 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. + if (activeElement && activeElement.value !== activeElementValue) { + activeElementValue = activeElement.value; + return 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. + return elem.nodeName && elem.nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); + } + + function getTargetInstForClickEvent(topLevelType, targetInst) { + if (topLevelType === topLevelTypes.topClick) { + return targetInst; + } + } + + /** + * 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, + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var targetNode = targetInst ? ReactDOMComponentTree.getNodeFromInstance(targetInst) : window; + + var getTargetInstFunc, handleEventFunc; + if (shouldUseChangeEvent(targetNode)) { + if (doesChangeEventBubble) { + getTargetInstFunc = getTargetInstForChangeEvent; + } else { + handleEventFunc = handleEventsForChangeEventIE8; + } + } else if (isTextInputElement(targetNode)) { + if (isInputEventSupported) { + getTargetInstFunc = getTargetInstForInputEvent; + } else { + getTargetInstFunc = getTargetInstForInputEventIE; + handleEventFunc = handleEventsForInputEventIE; + } + } else if (shouldUseClickEvent(targetNode)) { + getTargetInstFunc = getTargetInstForClickEvent; + } + + if (getTargetInstFunc) { + var inst = getTargetInstFunc(topLevelType, targetInst); + if (inst) { + var event = SyntheticEvent.getPooled(eventTypes.change, inst, nativeEvent, nativeEventTarget); + event.type = 'change'; + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + } + + if (handleEventFunc) { + handleEventFunc(topLevelType, targetNode, targetInst); + } + } + + }; + + module.exports = ChangeEventPlugin; + +/***/ }, +/* 56 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactUpdates + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7), + _assign = __webpack_require__(4); + + var CallbackQueue = __webpack_require__(57); + var PooledClass = __webpack_require__(6); + var ReactFeatureFlags = __webpack_require__(58); + var ReactReconciler = __webpack_require__(59); + var Transaction = __webpack_require__(69); + + var invariant = __webpack_require__(8); + + var dirtyComponents = []; + var updateBatchNumber = 0; + var asapCallbackQueue = CallbackQueue.getPooled(); + var asapEnqueued = false; + + var batchingStrategy = null; + + function ensureInjected() { + !(ReactUpdates.ReactReconcileTransaction && batchingStrategy) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactUpdates: must inject a reconcile transaction class and batching strategy') : _prodInvariant('123') : void 0; + } + + var NESTED_UPDATES = { + initialize: function () { + this.dirtyComponentsLength = dirtyComponents.length; + }, + close: function () { + if (this.dirtyComponentsLength !== dirtyComponents.length) { + // Additional updates were enqueued by componentDidUpdate handlers or + // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run + // these new updates so that if A's componentDidUpdate calls setState on + // B, B will update before the callback A's updater provided when calling + // setState. + dirtyComponents.splice(0, this.dirtyComponentsLength); + flushBatchedUpdates(); + } else { + dirtyComponents.length = 0; + } + } + }; + + var UPDATE_QUEUEING = { + initialize: function () { + this.callbackQueue.reset(); + }, + close: function () { + this.callbackQueue.notifyAll(); + } + }; + + var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING]; + + function ReactUpdatesFlushTransaction() { + this.reinitializeTransaction(); + this.dirtyComponentsLength = null; + this.callbackQueue = CallbackQueue.getPooled(); + this.reconcileTransaction = ReactUpdates.ReactReconcileTransaction.getPooled( + /* useCreateElement */true); + } + + _assign(ReactUpdatesFlushTransaction.prototype, Transaction.Mixin, { + getTransactionWrappers: function () { + return TRANSACTION_WRAPPERS; + }, + + destructor: function () { + this.dirtyComponentsLength = null; + CallbackQueue.release(this.callbackQueue); + this.callbackQueue = null; + ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction); + this.reconcileTransaction = null; + }, + + perform: function (method, scope, a) { + // Essentially calls `this.reconcileTransaction.perform(method, scope, a)` + // with this transaction's wrappers around it. + return Transaction.Mixin.perform.call(this, this.reconcileTransaction.perform, this.reconcileTransaction, method, scope, a); + } + }); + + PooledClass.addPoolingTo(ReactUpdatesFlushTransaction); + + function batchedUpdates(callback, a, b, c, d, e) { + ensureInjected(); + batchingStrategy.batchedUpdates(callback, a, b, c, d, e); + } + + /** + * Array comparator for ReactComponents by mount ordering. + * + * @param {ReactComponent} c1 first component you're comparing + * @param {ReactComponent} c2 second component you're comparing + * @return {number} Return value usable by Array.prototype.sort(). + */ + function mountOrderComparator(c1, c2) { + return c1._mountOrder - c2._mountOrder; + } + + function runBatchedUpdates(transaction) { + var len = transaction.dirtyComponentsLength; + !(len === dirtyComponents.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected flush transaction\'s stored dirty-components length (%s) to match dirty-components array length (%s).', len, dirtyComponents.length) : _prodInvariant('124', len, dirtyComponents.length) : void 0; + + // Since reconciling a component higher in the owner hierarchy usually (not + // always -- see shouldComponentUpdate()) will reconcile children, reconcile + // them before their children by sorting the array. + dirtyComponents.sort(mountOrderComparator); + + // Any updates enqueued while reconciling must be performed after this entire + // batch. Otherwise, if dirtyComponents is [A, B] where A has children B and + // C, B could update twice in a single batch if C's render enqueues an update + // to B (since B would have already updated, we should skip it, and the only + // way we can know to do so is by checking the batch counter). + updateBatchNumber++; + + for (var i = 0; i < len; i++) { + // If a component is unmounted before pending changes apply, it will still + // be here, but we assume that it has cleared its _pendingCallbacks and + // that performUpdateIfNecessary is a noop. + var component = dirtyComponents[i]; + + // If performUpdateIfNecessary happens to enqueue any new updates, we + // shouldn't execute the callbacks until the next render happens, so + // stash the callbacks first + var callbacks = component._pendingCallbacks; + component._pendingCallbacks = null; + + var markerName; + if (ReactFeatureFlags.logTopLevelRenders) { + var namedComponent = component; + // Duck type TopLevelWrapper. This is probably always true. + if (component._currentElement.props === component._renderedComponent._currentElement) { + namedComponent = component._renderedComponent; + } + markerName = 'React update: ' + namedComponent.getName(); + console.time(markerName); + } + + ReactReconciler.performUpdateIfNecessary(component, transaction.reconcileTransaction, updateBatchNumber); + + if (markerName) { + console.timeEnd(markerName); + } + + if (callbacks) { + for (var j = 0; j < callbacks.length; j++) { + transaction.callbackQueue.enqueue(callbacks[j], component.getPublicInstance()); + } + } + } + } + + var flushBatchedUpdates = function () { + // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents + // array and perform any updates enqueued by mount-ready handlers (i.e., + // componentDidUpdate) but we need to check here too in order to catch + // updates enqueued by setState callbacks and asap calls. + while (dirtyComponents.length || asapEnqueued) { + if (dirtyComponents.length) { + var transaction = ReactUpdatesFlushTransaction.getPooled(); + transaction.perform(runBatchedUpdates, null, transaction); + ReactUpdatesFlushTransaction.release(transaction); + } + + if (asapEnqueued) { + asapEnqueued = false; + var queue = asapCallbackQueue; + asapCallbackQueue = CallbackQueue.getPooled(); + queue.notifyAll(); + CallbackQueue.release(queue); + } + } + }; + + /** + * Mark a component as needing a rerender, adding an optional callback to a + * list of functions which will be executed once the rerender occurs. + */ + function enqueueUpdate(component) { + ensureInjected(); + + // Various parts of our code (such as ReactCompositeComponent's + // _renderValidatedComponent) assume that calls to render aren't nested; + // verify that that's the case. (This is called by each top-level update + // function, like setState, forceUpdate, etc.; creation and + // destruction of top-level components is guarded in ReactMount.) + + if (!batchingStrategy.isBatchingUpdates) { + batchingStrategy.batchedUpdates(enqueueUpdate, component); + return; + } + + dirtyComponents.push(component); + if (component._updateBatchNumber == null) { + component._updateBatchNumber = updateBatchNumber + 1; + } + } + + /** + * Enqueue a callback to be run at the end of the current batching cycle. Throws + * if no updates are currently being performed. + */ + function asap(callback, context) { + !batchingStrategy.isBatchingUpdates ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactUpdates.asap: Can\'t enqueue an asap callback in a context whereupdates are not being batched.') : _prodInvariant('125') : void 0; + asapCallbackQueue.enqueue(callback, context); + asapEnqueued = true; + } + + var ReactUpdatesInjection = { + injectReconcileTransaction: function (ReconcileTransaction) { + !ReconcileTransaction ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactUpdates: must provide a reconcile transaction class') : _prodInvariant('126') : void 0; + ReactUpdates.ReactReconcileTransaction = ReconcileTransaction; + }, + + injectBatchingStrategy: function (_batchingStrategy) { + !_batchingStrategy ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactUpdates: must provide a batching strategy') : _prodInvariant('127') : void 0; + !(typeof _batchingStrategy.batchedUpdates === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactUpdates: must provide a batchedUpdates() function') : _prodInvariant('128') : void 0; + !(typeof _batchingStrategy.isBatchingUpdates === 'boolean') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactUpdates: must provide an isBatchingUpdates boolean attribute') : _prodInvariant('129') : void 0; + batchingStrategy = _batchingStrategy; + } + }; + + var ReactUpdates = { + /** + * React references `ReactReconcileTransaction` using this property in order + * to allow dependency injection. + * + * @internal + */ + ReactReconcileTransaction: null, + + batchedUpdates: batchedUpdates, + enqueueUpdate: enqueueUpdate, + flushBatchedUpdates: flushBatchedUpdates, + injection: ReactUpdatesInjection, + asap: asap + }; + + module.exports = ReactUpdates; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 57 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule CallbackQueue + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7), + _assign = __webpack_require__(4); + + var PooledClass = __webpack_require__(6); + + var invariant = __webpack_require__(8); + + /** + * A specialized pseudo-event module to help keep track of components waiting to + * be notified when their DOM representations are available for use. + * + * This implements `PooledClass`, so you should never need to instantiate this. + * Instead, use `CallbackQueue.getPooled()`. + * + * @class ReactMountReady + * @implements PooledClass + * @internal + */ + function CallbackQueue() { + this._callbacks = null; + this._contexts = null; + } + + _assign(CallbackQueue.prototype, { + + /** + * Enqueues a callback to be invoked when `notifyAll` is invoked. + * + * @param {function} callback Invoked when `notifyAll` is invoked. + * @param {?object} context Context to call `callback` with. + * @internal + */ + enqueue: function (callback, context) { + this._callbacks = this._callbacks || []; + this._contexts = this._contexts || []; + this._callbacks.push(callback); + this._contexts.push(context); + }, + + /** + * Invokes all enqueued callbacks and clears the queue. This is invoked after + * the DOM representation of a component has been created or updated. + * + * @internal + */ + notifyAll: function () { + var callbacks = this._callbacks; + var contexts = this._contexts; + if (callbacks) { + !(callbacks.length === contexts.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Mismatched list of contexts in callback queue') : _prodInvariant('24') : void 0; + this._callbacks = null; + this._contexts = null; + for (var i = 0; i < callbacks.length; i++) { + callbacks[i].call(contexts[i]); + } + callbacks.length = 0; + contexts.length = 0; + } + }, + + checkpoint: function () { + return this._callbacks ? this._callbacks.length : 0; + }, + + rollback: function (len) { + if (this._callbacks) { + this._callbacks.length = len; + this._contexts.length = len; + } + }, + + /** + * Resets the internal queue. + * + * @internal + */ + reset: function () { + this._callbacks = null; + this._contexts = null; + }, + + /** + * `PooledClass` looks for this. + */ + destructor: function () { + this.reset(); + } + + }); + + PooledClass.addPoolingTo(CallbackQueue); + + module.exports = CallbackQueue; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 58 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactFeatureFlags + * + */ + + 'use strict'; + + var ReactFeatureFlags = { + // When true, call console.time() before and .timeEnd() after each top-level + // render (both initial renders and updates). Useful when looking at prod-mode + // timeline profiles in Chrome, for example. + logTopLevelRenders: false + }; + + module.exports = ReactFeatureFlags; + +/***/ }, +/* 59 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactReconciler + */ + + 'use strict'; + + var ReactRef = __webpack_require__(60); + var ReactInstrumentation = __webpack_require__(62); + + var warning = __webpack_require__(11); + + /** + * Helper to call ReactRef.attachRefs with this composite component, split out + * to avoid allocations in the transaction mount-ready queue. + */ + function attachRefs() { + ReactRef.attachRefs(this, this._currentElement); + } + + var ReactReconciler = { + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {ReactComponent} internalInstance + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @param {?object} the containing host component instance + * @param {?object} info about the host container + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function (internalInstance, transaction, hostParent, hostContainerInfo, context, parentDebugID // 0 in production and for roots + ) { + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeforeMountComponent(internalInstance._debugID, internalInstance._currentElement, parentDebugID); + } + } + var markup = internalInstance.mountComponent(transaction, hostParent, hostContainerInfo, context, parentDebugID); + if (internalInstance._currentElement && internalInstance._currentElement.ref != null) { + transaction.getReactMountReady().enqueue(attachRefs, internalInstance); + } + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID); + } + } + return markup; + }, + + /** + * Returns a value that can be passed to + * ReactComponentEnvironment.replaceNodeWithMarkup. + */ + getHostNode: function (internalInstance) { + return internalInstance.getHostNode(); + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function (internalInstance, safely) { + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeforeUnmountComponent(internalInstance._debugID); + } + } + ReactRef.detachRefs(internalInstance, internalInstance._currentElement); + internalInstance.unmountComponent(safely); + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onUnmountComponent(internalInstance._debugID); + } + } + }, + + /** + * Update a component using a new element. + * + * @param {ReactComponent} internalInstance + * @param {ReactElement} nextElement + * @param {ReactReconcileTransaction} transaction + * @param {object} context + * @internal + */ + receiveComponent: function (internalInstance, nextElement, transaction, context) { + var prevElement = internalInstance._currentElement; + + if (nextElement === prevElement && context === internalInstance._context) { + // Since elements are immutable after the owner is rendered, + // we can do a cheap identity compare here to determine if this is a + // superfluous reconcile. It's possible for state to be mutable but such + // change should trigger an update of the owner which would recreate + // the element. We explicitly check for the existence of an owner since + // it's possible for an element created outside a composite to be + // deeply mutated and reused. + + // TODO: Bailing out early is just a perf optimization right? + // TODO: Removing the return statement should affect correctness? + return; + } + + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeforeUpdateComponent(internalInstance._debugID, nextElement); + } + } + + var refsChanged = ReactRef.shouldUpdateRefs(prevElement, nextElement); + + if (refsChanged) { + ReactRef.detachRefs(internalInstance, prevElement); + } + + internalInstance.receiveComponent(nextElement, transaction, context); + + if (refsChanged && internalInstance._currentElement && internalInstance._currentElement.ref != null) { + transaction.getReactMountReady().enqueue(attachRefs, internalInstance); + } + + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID); + } + } + }, + + /** + * Flush any dirty changes in a component. + * + * @param {ReactComponent} internalInstance + * @param {ReactReconcileTransaction} transaction + * @internal + */ + performUpdateIfNecessary: function (internalInstance, transaction, updateBatchNumber) { + if (internalInstance._updateBatchNumber !== updateBatchNumber) { + // The component's enqueued batch number should always be the current + // batch or the following one. + process.env.NODE_ENV !== 'production' ? warning(internalInstance._updateBatchNumber == null || internalInstance._updateBatchNumber === updateBatchNumber + 1, 'performUpdateIfNecessary: Unexpected batch number (current %s, ' + 'pending %s)', updateBatchNumber, internalInstance._updateBatchNumber) : void 0; + return; + } + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeforeUpdateComponent(internalInstance._debugID, internalInstance._currentElement); + } + } + internalInstance.performUpdateIfNecessary(transaction); + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID); + } + } + } + + }; + + module.exports = ReactReconciler; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 60 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactRef + */ + + 'use strict'; + + var ReactOwner = __webpack_require__(61); + + var ReactRef = {}; + + function attachRef(ref, component, owner) { + if (typeof ref === 'function') { + ref(component.getPublicInstance()); + } else { + // Legacy ref + ReactOwner.addComponentAsRefTo(component, ref, owner); + } + } + + function detachRef(ref, component, owner) { + if (typeof ref === 'function') { + ref(null); + } else { + // Legacy ref + ReactOwner.removeComponentAsRefFrom(component, ref, owner); + } + } + + ReactRef.attachRefs = function (instance, element) { + if (element === null || element === false) { + return; + } + var ref = element.ref; + if (ref != null) { + attachRef(ref, instance, element._owner); + } + }; + + ReactRef.shouldUpdateRefs = function (prevElement, nextElement) { + // If either the owner or a `ref` has changed, make sure the newest owner + // has stored a reference to `this`, and the previous owner (if different) + // has forgotten the reference to `this`. We use the element instead + // of the public this.props because the post processing cannot determine + // a ref. The ref conceptually lives on the element. + + // TODO: Should this even be possible? The owner cannot change because + // it's forbidden by shouldUpdateReactComponent. The ref can change + // if you swap the keys of but not the refs. Reconsider where this check + // is made. It probably belongs where the key checking and + // instantiateReactComponent is done. + + var prevEmpty = prevElement === null || prevElement === false; + var nextEmpty = nextElement === null || nextElement === false; + + return ( + // This has a few false positives w/r/t empty components. + prevEmpty || nextEmpty || nextElement.ref !== prevElement.ref || + // If owner changes but we have an unchanged function ref, don't update refs + typeof nextElement.ref === 'string' && nextElement._owner !== prevElement._owner + ); + }; + + ReactRef.detachRefs = function (instance, element) { + if (element === null || element === false) { + return; + } + var ref = element.ref; + if (ref != null) { + detachRef(ref, instance, element._owner); + } + }; + + module.exports = ReactRef; + +/***/ }, +/* 61 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactOwner + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var invariant = __webpack_require__(8); + + /** + * ReactOwners are capable of storing references to owned components. + * + * All components are capable of //being// referenced by owner components, but + * only ReactOwner components are capable of //referencing// owned components. + * The named reference is known as a "ref". + * + * Refs are available when mounted and updated during reconciliation. + * + * var MyComponent = React.createClass({ + * render: function() { + * return ( + *
+ * + *
+ * ); + * }, + * handleClick: function() { + * this.refs.custom.handleClick(); + * }, + * componentDidMount: function() { + * this.refs.custom.initialize(); + * } + * }); + * + * Refs should rarely be used. When refs are used, they should only be done to + * control data that is not handled by React's data flow. + * + * @class ReactOwner + */ + var ReactOwner = { + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid owner. + * @final + */ + isValidOwner: function (object) { + return !!(object && typeof object.attachRef === 'function' && typeof object.detachRef === 'function'); + }, + + /** + * Adds a component by ref to an owner component. + * + * @param {ReactComponent} component Component to reference. + * @param {string} ref Name by which to refer to the component. + * @param {ReactOwner} owner Component on which to record the ref. + * @final + * @internal + */ + addComponentAsRefTo: function (component, ref, owner) { + !ReactOwner.isValidOwner(owner) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component\'s `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).') : _prodInvariant('119') : void 0; + owner.attachRef(ref, component); + }, + + /** + * Removes a component by ref from an owner component. + * + * @param {ReactComponent} component Component to dereference. + * @param {string} ref Name of the ref to remove. + * @param {ReactOwner} owner Component on which the ref is recorded. + * @final + * @internal + */ + removeComponentAsRefFrom: function (component, ref, owner) { + !ReactOwner.isValidOwner(owner) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. You might be removing a ref to a component that was not created inside a component\'s `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).') : _prodInvariant('120') : void 0; + var ownerPublicInstance = owner.getPublicInstance(); + // Check that `component`'s owner is still alive and that `component` is still the current ref + // because we do not want to detach the ref if another component stole it. + if (ownerPublicInstance && ownerPublicInstance.refs[ref] === component.getPublicInstance()) { + owner.detachRef(ref); + } + } + + }; + + module.exports = ReactOwner; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactInstrumentation + */ + + 'use strict'; + + var debugTool = null; + + if (process.env.NODE_ENV !== 'production') { + var ReactDebugTool = __webpack_require__(63); + debugTool = ReactDebugTool; + } + + module.exports = { debugTool: debugTool }; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 63 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDebugTool + */ + + 'use strict'; + + var ReactInvalidSetStateWarningHook = __webpack_require__(64); + var ReactHostOperationHistoryHook = __webpack_require__(65); + var ReactComponentTreeHook = __webpack_require__(28); + var ReactChildrenMutationWarningHook = __webpack_require__(66); + var ExecutionEnvironment = __webpack_require__(49); + + var performanceNow = __webpack_require__(67); + var warning = __webpack_require__(11); + + var hooks = []; + var didHookThrowForEvent = {}; + + function callHook(event, fn, context, arg1, arg2, arg3, arg4, arg5) { + try { + fn.call(context, arg1, arg2, arg3, arg4, arg5); + } catch (e) { + process.env.NODE_ENV !== 'production' ? warning(didHookThrowForEvent[event], 'Exception thrown by hook while handling %s: %s', event, e + '\n' + e.stack) : void 0; + didHookThrowForEvent[event] = true; + } + } + + function emitEvent(event, arg1, arg2, arg3, arg4, arg5) { + for (var i = 0; i < hooks.length; i++) { + var hook = hooks[i]; + var fn = hook[event]; + if (fn) { + callHook(event, fn, hook, arg1, arg2, arg3, arg4, arg5); + } + } + } + + var isProfiling = false; + var flushHistory = []; + var lifeCycleTimerStack = []; + var currentFlushNesting = 0; + var currentFlushMeasurements = null; + var currentFlushStartTime = null; + var currentTimerDebugID = null; + var currentTimerStartTime = null; + var currentTimerNestedFlushDuration = null; + var currentTimerType = null; + + var lifeCycleTimerHasWarned = false; + + function clearHistory() { + ReactComponentTreeHook.purgeUnmountedComponents(); + ReactHostOperationHistoryHook.clearHistory(); + } + + function getTreeSnapshot(registeredIDs) { + return registeredIDs.reduce(function (tree, id) { + var ownerID = ReactComponentTreeHook.getOwnerID(id); + var parentID = ReactComponentTreeHook.getParentID(id); + tree[id] = { + displayName: ReactComponentTreeHook.getDisplayName(id), + text: ReactComponentTreeHook.getText(id), + updateCount: ReactComponentTreeHook.getUpdateCount(id), + childIDs: ReactComponentTreeHook.getChildIDs(id), + // Text nodes don't have owners but this is close enough. + ownerID: ownerID || ReactComponentTreeHook.getOwnerID(parentID), + parentID: parentID + }; + return tree; + }, {}); + } + + function resetMeasurements() { + var previousStartTime = currentFlushStartTime; + var previousMeasurements = currentFlushMeasurements || []; + var previousOperations = ReactHostOperationHistoryHook.getHistory(); + + if (currentFlushNesting === 0) { + currentFlushStartTime = null; + currentFlushMeasurements = null; + clearHistory(); + return; + } + + if (previousMeasurements.length || previousOperations.length) { + var registeredIDs = ReactComponentTreeHook.getRegisteredIDs(); + flushHistory.push({ + duration: performanceNow() - previousStartTime, + measurements: previousMeasurements || [], + operations: previousOperations || [], + treeSnapshot: getTreeSnapshot(registeredIDs) + }); + } + + clearHistory(); + currentFlushStartTime = performanceNow(); + currentFlushMeasurements = []; + } + + function checkDebugID(debugID) { + var allowRoot = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; + + if (allowRoot && debugID === 0) { + return; + } + if (!debugID) { + process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDebugTool: debugID may not be empty.') : void 0; + } + } + + function beginLifeCycleTimer(debugID, timerType) { + if (currentFlushNesting === 0) { + return; + } + if (currentTimerType && !lifeCycleTimerHasWarned) { + process.env.NODE_ENV !== 'production' ? warning(false, 'There is an internal error in the React performance measurement code. ' + 'Did not expect %s timer to start while %s timer is still in ' + 'progress for %s instance.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another') : void 0; + lifeCycleTimerHasWarned = true; + } + currentTimerStartTime = performanceNow(); + currentTimerNestedFlushDuration = 0; + currentTimerDebugID = debugID; + currentTimerType = timerType; + } + + function endLifeCycleTimer(debugID, timerType) { + if (currentFlushNesting === 0) { + return; + } + if (currentTimerType !== timerType && !lifeCycleTimerHasWarned) { + process.env.NODE_ENV !== 'production' ? warning(false, 'There is an internal error in the React performance measurement code. ' + 'We did not expect %s timer to stop while %s timer is still in ' + 'progress for %s instance. Please report this as a bug in React.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another') : void 0; + lifeCycleTimerHasWarned = true; + } + if (isProfiling) { + currentFlushMeasurements.push({ + timerType: timerType, + instanceID: debugID, + duration: performanceNow() - currentTimerStartTime - currentTimerNestedFlushDuration + }); + } + currentTimerStartTime = null; + currentTimerNestedFlushDuration = null; + currentTimerDebugID = null; + currentTimerType = null; + } + + function pauseCurrentLifeCycleTimer() { + var currentTimer = { + startTime: currentTimerStartTime, + nestedFlushStartTime: performanceNow(), + debugID: currentTimerDebugID, + timerType: currentTimerType + }; + lifeCycleTimerStack.push(currentTimer); + currentTimerStartTime = null; + currentTimerNestedFlushDuration = null; + currentTimerDebugID = null; + currentTimerType = null; + } + + function resumeCurrentLifeCycleTimer() { + var _lifeCycleTimerStack$ = lifeCycleTimerStack.pop(); + + var startTime = _lifeCycleTimerStack$.startTime; + var nestedFlushStartTime = _lifeCycleTimerStack$.nestedFlushStartTime; + var debugID = _lifeCycleTimerStack$.debugID; + var timerType = _lifeCycleTimerStack$.timerType; + + var nestedFlushDuration = performanceNow() - nestedFlushStartTime; + currentTimerStartTime = startTime; + currentTimerNestedFlushDuration += nestedFlushDuration; + currentTimerDebugID = debugID; + currentTimerType = timerType; + } + + var ReactDebugTool = { + addHook: function (hook) { + hooks.push(hook); + }, + removeHook: function (hook) { + for (var i = 0; i < hooks.length; i++) { + if (hooks[i] === hook) { + hooks.splice(i, 1); + i--; + } + } + }, + isProfiling: function () { + return isProfiling; + }, + beginProfiling: function () { + if (isProfiling) { + return; + } + + isProfiling = true; + flushHistory.length = 0; + resetMeasurements(); + ReactDebugTool.addHook(ReactHostOperationHistoryHook); + }, + endProfiling: function () { + if (!isProfiling) { + return; + } + + isProfiling = false; + resetMeasurements(); + ReactDebugTool.removeHook(ReactHostOperationHistoryHook); + }, + getFlushHistory: function () { + return flushHistory; + }, + onBeginFlush: function () { + currentFlushNesting++; + resetMeasurements(); + pauseCurrentLifeCycleTimer(); + emitEvent('onBeginFlush'); + }, + onEndFlush: function () { + resetMeasurements(); + currentFlushNesting--; + resumeCurrentLifeCycleTimer(); + emitEvent('onEndFlush'); + }, + onBeginLifeCycleTimer: function (debugID, timerType) { + checkDebugID(debugID); + emitEvent('onBeginLifeCycleTimer', debugID, timerType); + beginLifeCycleTimer(debugID, timerType); + }, + onEndLifeCycleTimer: function (debugID, timerType) { + checkDebugID(debugID); + endLifeCycleTimer(debugID, timerType); + emitEvent('onEndLifeCycleTimer', debugID, timerType); + }, + onBeginProcessingChildContext: function () { + emitEvent('onBeginProcessingChildContext'); + }, + onEndProcessingChildContext: function () { + emitEvent('onEndProcessingChildContext'); + }, + onHostOperation: function (debugID, type, payload) { + checkDebugID(debugID); + emitEvent('onHostOperation', debugID, type, payload); + }, + onSetState: function () { + emitEvent('onSetState'); + }, + onSetChildren: function (debugID, childDebugIDs) { + checkDebugID(debugID); + childDebugIDs.forEach(checkDebugID); + emitEvent('onSetChildren', debugID, childDebugIDs); + }, + onBeforeMountComponent: function (debugID, element, parentDebugID) { + checkDebugID(debugID); + checkDebugID(parentDebugID, true); + emitEvent('onBeforeMountComponent', debugID, element, parentDebugID); + }, + onMountComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onMountComponent', debugID); + }, + onBeforeUpdateComponent: function (debugID, element) { + checkDebugID(debugID); + emitEvent('onBeforeUpdateComponent', debugID, element); + }, + onUpdateComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onUpdateComponent', debugID); + }, + onBeforeUnmountComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onBeforeUnmountComponent', debugID); + }, + onUnmountComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onUnmountComponent', debugID); + }, + onTestEvent: function () { + emitEvent('onTestEvent'); + } + }; + + // TODO remove these when RN/www gets updated + ReactDebugTool.addDevtool = ReactDebugTool.addHook; + ReactDebugTool.removeDevtool = ReactDebugTool.removeHook; + + ReactDebugTool.addHook(ReactInvalidSetStateWarningHook); + ReactDebugTool.addHook(ReactComponentTreeHook); + ReactDebugTool.addHook(ReactChildrenMutationWarningHook); + var url = ExecutionEnvironment.canUseDOM && window.location.href || ''; + if (/[?&]react_perf\b/.test(url)) { + ReactDebugTool.beginProfiling(); + } + + module.exports = ReactDebugTool; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 64 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactInvalidSetStateWarningHook + */ + + 'use strict'; + + var warning = __webpack_require__(11); + + if (process.env.NODE_ENV !== 'production') { + var processingChildContext = false; + + var warnInvalidSetState = function () { + process.env.NODE_ENV !== 'production' ? warning(!processingChildContext, 'setState(...): Cannot call setState() inside getChildContext()') : void 0; + }; + } + + var ReactInvalidSetStateWarningHook = { + onBeginProcessingChildContext: function () { + processingChildContext = true; + }, + onEndProcessingChildContext: function () { + processingChildContext = false; + }, + onSetState: function () { + warnInvalidSetState(); + } + }; + + module.exports = ReactInvalidSetStateWarningHook; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 65 */ +/***/ function(module, exports) { + + /** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactHostOperationHistoryHook + */ + + 'use strict'; + + var history = []; + + var ReactHostOperationHistoryHook = { + onHostOperation: function (debugID, type, payload) { + history.push({ + instanceID: debugID, + type: type, + payload: payload + }); + }, + clearHistory: function () { + if (ReactHostOperationHistoryHook._preventClearing) { + // Should only be used for tests. + return; + } + + history = []; + }, + getHistory: function () { + return history; + } + }; + + module.exports = ReactHostOperationHistoryHook; + +/***/ }, +/* 66 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactChildrenMutationWarningHook + */ + + 'use strict'; + + var ReactComponentTreeHook = __webpack_require__(28); + + var warning = __webpack_require__(11); + + function handleElement(debugID, element) { + if (element == null) { + return; + } + if (element._shadowChildren === undefined) { + return; + } + if (element._shadowChildren === element.props.children) { + return; + } + var isMutated = false; + if (Array.isArray(element._shadowChildren)) { + if (element._shadowChildren.length === element.props.children.length) { + for (var i = 0; i < element._shadowChildren.length; i++) { + if (element._shadowChildren[i] !== element.props.children[i]) { + isMutated = true; + } + } + } else { + isMutated = true; + } + } + if (!Array.isArray(element._shadowChildren) || isMutated) { + process.env.NODE_ENV !== 'production' ? warning(false, 'Component\'s children should not be mutated.%s', ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0; + } + } + + var ReactChildrenMutationWarningHook = { + onMountComponent: function (debugID) { + handleElement(debugID, ReactComponentTreeHook.getElement(debugID)); + }, + onUpdateComponent: function (debugID) { + handleElement(debugID, ReactComponentTreeHook.getElement(debugID)); + } + }; + + module.exports = ReactChildrenMutationWarningHook; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 67 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @typechecks + */ + + var performance = __webpack_require__(68); + + var performanceNow; + + /** + * Detect if we can use `window.performance.now()` and gracefully fallback to + * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now + * because of Facebook's testing infrastructure. + */ + if (performance.now) { + performanceNow = function performanceNow() { + return performance.now(); + }; + } else { + performanceNow = function performanceNow() { + return Date.now(); + }; + } + + module.exports = performanceNow; + +/***/ }, +/* 68 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @typechecks + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(49); + + var performance; + + if (ExecutionEnvironment.canUseDOM) { + performance = window.performance || window.msPerformance || window.webkitPerformance; + } + + module.exports = performance || {}; + +/***/ }, +/* 69 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Transaction + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var invariant = __webpack_require__(8); + + /** + * `Transaction` creates a black box that is able to wrap any method such that + * certain invariants are maintained before and after the method is invoked + * (Even if an exception is thrown while invoking the wrapped method). Whoever + * instantiates a transaction can provide enforcers of the invariants at + * creation time. The `Transaction` class itself will supply one additional + * automatic invariant for you - the invariant that any transaction instance + * should not be run while it is already being run. You would typically create a + * single instance of a `Transaction` for reuse multiple times, that potentially + * is used to wrap several different methods. Wrappers are extremely simple - + * they only require implementing two methods. + * + *
+	 *                       wrappers (injected at creation time)
+	 *                                      +        +
+	 *                                      |        |
+	 *                    +-----------------|--------|--------------+
+	 *                    |                 v        |              |
+	 *                    |      +---------------+   |              |
+	 *                    |   +--|    wrapper1   |---|----+         |
+	 *                    |   |  +---------------+   v    |         |
+	 *                    |   |          +-------------+  |         |
+	 *                    |   |     +----|   wrapper2  |--------+   |
+	 *                    |   |     |    +-------------+  |     |   |
+	 *                    |   |     |                     |     |   |
+	 *                    |   v     v                     v     v   | wrapper
+	 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
+	 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
+	 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
+	 *                    | |   | |   |   |         |   |   | |   | |
+	 *                    | |   | |   |   |         |   |   | |   | |
+	 *                    | |   | |   |   |         |   |   | |   | |
+	 *                    | +---+ +---+   +---------+   +---+ +---+ |
+	 *                    |  initialize                    close    |
+	 *                    +-----------------------------------------+
+	 * 
+ * + * Use cases: + * - Preserving the input selection ranges before/after reconciliation. + * Restoring selection even in the event of an unexpected error. + * - Deactivating events while rearranging the DOM, preventing blurs/focuses, + * while guaranteeing that afterwards, the event system is reactivated. + * - Flushing a queue of collected DOM mutations to the main UI thread after a + * reconciliation takes place in a worker thread. + * - Invoking any collected `componentDidUpdate` callbacks after rendering new + * content. + * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue + * to preserve the `scrollTop` (an automatic scroll aware DOM). + * - (Future use case): Layout calculations before and after DOM updates. + * + * Transactional plugin API: + * - A module that has an `initialize` method that returns any precomputation. + * - and a `close` method that accepts the precomputation. `close` is invoked + * when the wrapped process is completed, or has failed. + * + * @param {Array} transactionWrapper Wrapper modules + * that implement `initialize` and `close`. + * @return {Transaction} Single transaction for reuse in thread. + * + * @class Transaction + */ + var Mixin = { + /** + * Sets up this instance so that it is prepared for collecting metrics. Does + * so such that this setup method may be used on an instance that is already + * initialized, in a way that does not consume additional memory upon reuse. + * That can be useful if you decide to make your subclass of this mixin a + * "PooledClass". + */ + reinitializeTransaction: function () { + this.transactionWrappers = this.getTransactionWrappers(); + if (this.wrapperInitData) { + this.wrapperInitData.length = 0; + } else { + this.wrapperInitData = []; + } + this._isInTransaction = false; + }, + + _isInTransaction: false, + + /** + * @abstract + * @return {Array} Array of transaction wrappers. + */ + getTransactionWrappers: null, + + isInTransaction: function () { + return !!this._isInTransaction; + }, + + /** + * Executes the function within a safety window. Use this for the top level + * methods that result in large amounts of computation/mutations that would + * need to be safety checked. The optional arguments helps prevent the need + * to bind in many cases. + * + * @param {function} method Member of scope to call. + * @param {Object} scope Scope to invoke from. + * @param {Object?=} a Argument to pass to the method. + * @param {Object?=} b Argument to pass to the method. + * @param {Object?=} c Argument to pass to the method. + * @param {Object?=} d Argument to pass to the method. + * @param {Object?=} e Argument to pass to the method. + * @param {Object?=} f Argument to pass to the method. + * + * @return {*} Return value from `method`. + */ + perform: function (method, scope, a, b, c, d, e, f) { + !!this.isInTransaction() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Transaction.perform(...): Cannot initialize a transaction when there is already an outstanding transaction.') : _prodInvariant('27') : void 0; + var errorThrown; + var ret; + try { + this._isInTransaction = true; + // Catching errors makes debugging more difficult, so we start with + // errorThrown set to true before setting it to false after calling + // close -- if it's still set to true in the finally block, it means + // one of these calls threw. + errorThrown = true; + this.initializeAll(0); + ret = method.call(scope, a, b, c, d, e, f); + errorThrown = false; + } finally { + try { + if (errorThrown) { + // If `method` throws, prefer to show that stack trace over any thrown + // by invoking `closeAll`. + try { + this.closeAll(0); + } catch (err) {} + } else { + // Since `method` didn't throw, we don't want to silence the exception + // here. + this.closeAll(0); + } + } finally { + this._isInTransaction = false; + } + } + return ret; + }, + + initializeAll: function (startIndex) { + var transactionWrappers = this.transactionWrappers; + for (var i = startIndex; i < transactionWrappers.length; i++) { + var wrapper = transactionWrappers[i]; + try { + // Catching errors makes debugging more difficult, so we start with the + // OBSERVED_ERROR state before overwriting it with the real return value + // of initialize -- if it's still set to OBSERVED_ERROR in the finally + // block, it means wrapper.initialize threw. + this.wrapperInitData[i] = Transaction.OBSERVED_ERROR; + this.wrapperInitData[i] = wrapper.initialize ? wrapper.initialize.call(this) : null; + } finally { + if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) { + // The initializer for wrapper i threw an error; initialize the + // remaining wrappers but silence any exceptions from them to ensure + // that the first error is the one to bubble up. + try { + this.initializeAll(i + 1); + } catch (err) {} + } + } + } + }, + + /** + * Invokes each of `this.transactionWrappers.close[i]` functions, passing into + * them the respective return values of `this.transactionWrappers.init[i]` + * (`close`rs that correspond to initializers that failed will not be + * invoked). + */ + closeAll: function (startIndex) { + !this.isInTransaction() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Transaction.closeAll(): Cannot close transaction when none are open.') : _prodInvariant('28') : void 0; + var transactionWrappers = this.transactionWrappers; + for (var i = startIndex; i < transactionWrappers.length; i++) { + var wrapper = transactionWrappers[i]; + var initData = this.wrapperInitData[i]; + var errorThrown; + try { + // Catching errors makes debugging more difficult, so we start with + // errorThrown set to true before setting it to false after calling + // close -- if it's still set to true in the finally block, it means + // wrapper.close threw. + errorThrown = true; + if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) { + wrapper.close.call(this, initData); + } + errorThrown = false; + } finally { + if (errorThrown) { + // The closer for wrapper i threw an error; close the remaining + // wrappers but silence any exceptions from them to ensure that the + // first error is the one to bubble up. + try { + this.closeAll(i + 1); + } catch (e) {} + } + } + } + this.wrapperInitData.length = 0; + } + }; + + var Transaction = { + + Mixin: Mixin, + + /** + * Token to look for to determine if an error occurred. + */ + OBSERVED_ERROR: {} + + }; + + module.exports = Transaction; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 70 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule getEventTarget + */ + + 'use strict'; + + /** + * 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) { + 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 === 3 ? target.parentNode : target; + } + + module.exports = getEventTarget; + +/***/ }, +/* 71 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule isEventSupported + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(49); + + var useHasFeature; + if (ExecutionEnvironment.canUseDOM) { + useHasFeature = document.implementation && document.implementation.hasFeature && + // always returns true in newer browsers as per the standard. + // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature + document.implementation.hasFeature('', '') !== true; + } + + /** + * 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". + * @param {?boolean} capture Check if the capture phase is supported. + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ + function isEventSupported(eventNameSuffix, capture) { + if (!ExecutionEnvironment.canUseDOM || capture && !('addEventListener' in document)) { + 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'; + } + + if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') { + // This is the only way to test support for the `wheel` event in IE9+. + isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); + } + + return isSupported; + } + + module.exports = isEventSupported; + +/***/ }, +/* 72 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule isTextInputElement + * + */ + + 'use strict'; + + /** + * @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; + } + + module.exports = isTextInputElement; + +/***/ }, +/* 73 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DefaultEventPluginOrder + */ + + 'use strict'; + + var keyOf = __webpack_require__(25); + + /** + * 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 DefaultEventPluginOrder = [keyOf({ ResponderEventPlugin: null }), keyOf({ SimpleEventPlugin: null }), keyOf({ TapEventPlugin: null }), keyOf({ EnterLeaveEventPlugin: null }), keyOf({ ChangeEventPlugin: null }), keyOf({ SelectEventPlugin: null }), keyOf({ BeforeInputEventPlugin: null })]; + + module.exports = DefaultEventPluginOrder; + +/***/ }, +/* 74 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EnterLeaveEventPlugin + */ + + 'use strict'; + + var EventConstants = __webpack_require__(41); + var EventPropagators = __webpack_require__(42); + var ReactDOMComponentTree = __webpack_require__(36); + var SyntheticMouseEvent = __webpack_require__(75); + + var keyOf = __webpack_require__(25); + + var topLevelTypes = EventConstants.topLevelTypes; + + var eventTypes = { + mouseEnter: { + registrationName: keyOf({ onMouseEnter: null }), + dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver] + }, + mouseLeave: { + registrationName: keyOf({ onMouseLeave: null }), + dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver] + } + }; + + var EnterLeaveEventPlugin = { + + eventTypes: eventTypes, + + /** + * 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) { + if (topLevelType === topLevelTypes.topMouseOver && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { + return null; + } + if (topLevelType !== topLevelTypes.topMouseOut && topLevelType !== topLevelTypes.topMouseOver) { + // Must not be a mouse in or mouse out - ignoring. + return null; + } + + var win; + 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; + var to; + if (topLevelType === topLevelTypes.topMouseOut) { + from = targetInst; + var related = nativeEvent.relatedTarget || nativeEvent.toElement; + to = related ? ReactDOMComponentTree.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 fromNode = from == null ? win : ReactDOMComponentTree.getNodeFromInstance(from); + var toNode = to == null ? win : ReactDOMComponentTree.getNodeFromInstance(to); + + var leave = SyntheticMouseEvent.getPooled(eventTypes.mouseLeave, from, nativeEvent, nativeEventTarget); + leave.type = 'mouseleave'; + leave.target = fromNode; + leave.relatedTarget = toNode; + + var enter = SyntheticMouseEvent.getPooled(eventTypes.mouseEnter, to, nativeEvent, nativeEventTarget); + enter.type = 'mouseenter'; + enter.target = toNode; + enter.relatedTarget = fromNode; + + EventPropagators.accumulateEnterLeaveDispatches(leave, enter, from, to); + + return [leave, enter]; + } + + }; + + module.exports = EnterLeaveEventPlugin; + +/***/ }, +/* 75 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SyntheticMouseEvent + */ + + 'use strict'; + + var SyntheticUIEvent = __webpack_require__(76); + var ViewportMetrics = __webpack_require__(77); + + var getEventModifierState = __webpack_require__(78); + + /** + * @interface MouseEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ + var MouseEventInterface = { + screenX: null, + screenY: null, + clientX: null, + clientY: null, + ctrlKey: null, + shiftKey: null, + altKey: null, + metaKey: null, + getModifierState: getEventModifierState, + button: function (event) { + // Webkit, Firefox, IE9+ + // which: 1 2 3 + // button: 0 1 2 (standard) + var button = event.button; + if ('which' in event) { + return button; + } + // IE<9 + // which: undefined + // button: 0 0 0 + // button: 1 4 2 (onmouseup) + return button === 2 ? 2 : button === 4 ? 1 : 0; + }, + buttons: null, + relatedTarget: function (event) { + return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); + }, + // "Proprietary" Interface. + pageX: function (event) { + return 'pageX' in event ? event.pageX : event.clientX + ViewportMetrics.currentScrollLeft; + }, + pageY: function (event) { + return 'pageY' in event ? event.pageY : event.clientY + ViewportMetrics.currentScrollTop; + } + }; + + /** + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {string} dispatchMarker Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @extends {SyntheticUIEvent} + */ + function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); + } + + SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface); + + module.exports = SyntheticMouseEvent; + +/***/ }, +/* 76 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SyntheticUIEvent + */ + + 'use strict'; + + var SyntheticEvent = __webpack_require__(53); + + var getEventTarget = __webpack_require__(70); + + /** + * @interface UIEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ + var UIEventInterface = { + view: function (event) { + if (event.view) { + return event.view; + } + + var target = getEventTarget(event); + if (target.window === target) { + // target is a window object + return target; + } + + var doc = target.ownerDocument; + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. + if (doc) { + return doc.defaultView || doc.parentWindow; + } else { + return window; + } + }, + detail: function (event) { + return event.detail || 0; + } + }; + + /** + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {string} dispatchMarker Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @extends {SyntheticEvent} + */ + function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); + } + + SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface); + + module.exports = SyntheticUIEvent; + +/***/ }, +/* 77 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ViewportMetrics + */ + + 'use strict'; + + var ViewportMetrics = { + + currentScrollLeft: 0, + + currentScrollTop: 0, + + refreshScrollValues: function (scrollPosition) { + ViewportMetrics.currentScrollLeft = scrollPosition.x; + ViewportMetrics.currentScrollTop = scrollPosition.y; + } + + }; + + module.exports = ViewportMetrics; + +/***/ }, +/* 78 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule getEventModifierState + */ + + 'use strict'; + + /** + * Translation from modifier key to the associated property in the event. + * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers + */ + + var modifierKeyToProp = { + 'Alt': 'altKey', + 'Control': 'ctrlKey', + 'Meta': 'metaKey', + 'Shift': 'shiftKey' + }; + + // IE8 does not implement getModifierState so we simply map it to the only + // modifier keys exposed by the event itself, does not support Lock-keys. + // Currently, all major browsers except Chrome seems to support Lock-keys. + 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; + } + + module.exports = getEventModifierState; + +/***/ }, +/* 79 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule HTMLDOMPropertyConfig + */ + + 'use strict'; + + var DOMProperty = __webpack_require__(37); + + var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY; + var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE; + var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE; + var HAS_POSITIVE_NUMERIC_VALUE = DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE; + var HAS_OVERLOADED_BOOLEAN_VALUE = DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE; + + var HTMLDOMPropertyConfig = { + isCustomAttribute: RegExp.prototype.test.bind(new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')), + Properties: { + /** + * Standard Properties + */ + accept: 0, + acceptCharset: 0, + accessKey: 0, + action: 0, + allowFullScreen: HAS_BOOLEAN_VALUE, + allowTransparency: 0, + alt: 0, + // specifies target context for links with `preload` type + as: 0, + async: HAS_BOOLEAN_VALUE, + autoComplete: 0, + // autoFocus is polyfilled/normalized by AutoFocusUtils + // autoFocus: HAS_BOOLEAN_VALUE, + autoPlay: HAS_BOOLEAN_VALUE, + capture: HAS_BOOLEAN_VALUE, + cellPadding: 0, + cellSpacing: 0, + charSet: 0, + challenge: 0, + checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + cite: 0, + classID: 0, + className: 0, + cols: HAS_POSITIVE_NUMERIC_VALUE, + colSpan: 0, + content: 0, + contentEditable: 0, + contextMenu: 0, + controls: HAS_BOOLEAN_VALUE, + coords: 0, + crossOrigin: 0, + data: 0, // For `` acts as `src`. + dateTime: 0, + 'default': HAS_BOOLEAN_VALUE, + defer: HAS_BOOLEAN_VALUE, + dir: 0, + disabled: HAS_BOOLEAN_VALUE, + download: HAS_OVERLOADED_BOOLEAN_VALUE, + draggable: 0, + encType: 0, + form: 0, + formAction: 0, + formEncType: 0, + formMethod: 0, + formNoValidate: HAS_BOOLEAN_VALUE, + formTarget: 0, + frameBorder: 0, + headers: 0, + height: 0, + hidden: HAS_BOOLEAN_VALUE, + high: 0, + href: 0, + hrefLang: 0, + htmlFor: 0, + httpEquiv: 0, + icon: 0, + id: 0, + inputMode: 0, + integrity: 0, + is: 0, + keyParams: 0, + keyType: 0, + kind: 0, + label: 0, + lang: 0, + list: 0, + loop: HAS_BOOLEAN_VALUE, + low: 0, + manifest: 0, + marginHeight: 0, + marginWidth: 0, + max: 0, + maxLength: 0, + media: 0, + mediaGroup: 0, + method: 0, + min: 0, + minLength: 0, + // Caution; `option.selected` is not updated if `select.multiple` is + // disabled with `removeAttribute`. + multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + name: 0, + nonce: 0, + noValidate: HAS_BOOLEAN_VALUE, + open: HAS_BOOLEAN_VALUE, + optimum: 0, + pattern: 0, + placeholder: 0, + playsInline: HAS_BOOLEAN_VALUE, + poster: 0, + preload: 0, + profile: 0, + radioGroup: 0, + readOnly: HAS_BOOLEAN_VALUE, + referrerPolicy: 0, + rel: 0, + required: HAS_BOOLEAN_VALUE, + reversed: HAS_BOOLEAN_VALUE, + role: 0, + rows: HAS_POSITIVE_NUMERIC_VALUE, + rowSpan: HAS_NUMERIC_VALUE, + sandbox: 0, + scope: 0, + scoped: HAS_BOOLEAN_VALUE, + scrolling: 0, + seamless: HAS_BOOLEAN_VALUE, + selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + shape: 0, + size: HAS_POSITIVE_NUMERIC_VALUE, + sizes: 0, + span: HAS_POSITIVE_NUMERIC_VALUE, + spellCheck: 0, + src: 0, + srcDoc: 0, + srcLang: 0, + srcSet: 0, + start: HAS_NUMERIC_VALUE, + step: 0, + style: 0, + summary: 0, + tabIndex: 0, + target: 0, + title: 0, + // Setting .type throws on non- tags + type: 0, + useMap: 0, + value: 0, + width: 0, + wmode: 0, + wrap: 0, + + /** + * RDFa Properties + */ + about: 0, + datatype: 0, + inlist: 0, + prefix: 0, + // property is also supported for OpenGraph in meta tags. + property: 0, + resource: 0, + 'typeof': 0, + vocab: 0, + + /** + * Non-standard Properties + */ + // autoCapitalize and autoCorrect are supported in Mobile Safari for + // keyboard hints. + autoCapitalize: 0, + autoCorrect: 0, + // autoSave allows WebKit/Blink to persist values of input fields on page reloads + autoSave: 0, + // color is for Safari mask-icon link + color: 0, + // itemProp, itemScope, itemType are for + // Microdata support. See http://schema.org/docs/gs.html + itemProp: 0, + itemScope: HAS_BOOLEAN_VALUE, + itemType: 0, + // itemID and itemRef are for Microdata support as well but + // only specified in the WHATWG spec document. See + // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api + itemID: 0, + itemRef: 0, + // results show looking glass icon and recent searches on input + // search fields in WebKit/Blink + results: 0, + // IE-only attribute that specifies security restrictions on an iframe + // as an alternative to the sandbox attribute on IE<10 + security: 0, + // IE-only attribute that controls focus behavior + unselectable: 0 + }, + DOMAttributeNames: { + acceptCharset: 'accept-charset', + className: 'class', + htmlFor: 'for', + httpEquiv: 'http-equiv' + }, + DOMPropertyNames: {} + }; + + module.exports = HTMLDOMPropertyConfig; + +/***/ }, +/* 80 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentBrowserEnvironment + */ + + 'use strict'; + + var DOMChildrenOperations = __webpack_require__(81); + var ReactDOMIDOperations = __webpack_require__(93); + + /** + * Abstracts away all functionality of the reconciler that requires knowledge of + * the browser context. TODO: These callers should be refactored to avoid the + * need for this injection. + */ + var ReactComponentBrowserEnvironment = { + + processChildrenUpdates: ReactDOMIDOperations.dangerouslyProcessChildrenUpdates, + + replaceNodeWithMarkup: DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup + + }; + + module.exports = ReactComponentBrowserEnvironment; + +/***/ }, +/* 81 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMChildrenOperations + */ + + 'use strict'; + + var DOMLazyTree = __webpack_require__(82); + var Danger = __webpack_require__(88); + var ReactMultiChildUpdateTypes = __webpack_require__(92); + var ReactDOMComponentTree = __webpack_require__(36); + var ReactInstrumentation = __webpack_require__(62); + + var createMicrosoftUnsafeLocalFunction = __webpack_require__(85); + var setInnerHTML = __webpack_require__(84); + var setTextContent = __webpack_require__(86); + + function getNodeAfter(parentNode, node) { + // Special case for text components, which return [open, close] comments + // from getHostNode. + if (Array.isArray(node)) { + node = node[1]; + } + return node ? node.nextSibling : parentNode.firstChild; + } + + /** + * Inserts `childNode` as a child of `parentNode` at the `index`. + * + * @param {DOMElement} parentNode Parent node in which to insert. + * @param {DOMElement} childNode Child node to insert. + * @param {number} index Index at which to insert the child. + * @internal + */ + var insertChildAt = createMicrosoftUnsafeLocalFunction(function (parentNode, childNode, referenceNode) { + // We rely exclusively on `insertBefore(node, null)` instead of also using + // `appendChild(node)`. (Using `undefined` is not allowed by all browsers so + // we are careful to use `null`.) + parentNode.insertBefore(childNode, referenceNode); + }); + + function insertLazyTreeChildAt(parentNode, childTree, referenceNode) { + DOMLazyTree.insertTreeBefore(parentNode, childTree, referenceNode); + } + + function moveChild(parentNode, childNode, referenceNode) { + if (Array.isArray(childNode)) { + moveDelimitedText(parentNode, childNode[0], childNode[1], referenceNode); + } else { + insertChildAt(parentNode, childNode, referenceNode); + } + } + + function removeChild(parentNode, childNode) { + if (Array.isArray(childNode)) { + var closingComment = childNode[1]; + childNode = childNode[0]; + removeDelimitedText(parentNode, childNode, closingComment); + parentNode.removeChild(closingComment); + } + parentNode.removeChild(childNode); + } + + function moveDelimitedText(parentNode, openingComment, closingComment, referenceNode) { + var node = openingComment; + while (true) { + var nextNode = node.nextSibling; + insertChildAt(parentNode, node, referenceNode); + if (node === closingComment) { + break; + } + node = nextNode; + } + } + + function removeDelimitedText(parentNode, startNode, closingComment) { + while (true) { + var node = startNode.nextSibling; + if (node === closingComment) { + // The closing comment is removed by ReactMultiChild. + break; + } else { + parentNode.removeChild(node); + } + } + } + + function replaceDelimitedText(openingComment, closingComment, stringText) { + var parentNode = openingComment.parentNode; + var nodeAfterComment = openingComment.nextSibling; + if (nodeAfterComment === closingComment) { + // There are no text nodes between the opening and closing comments; insert + // a new one if stringText isn't empty. + if (stringText) { + insertChildAt(parentNode, document.createTextNode(stringText), nodeAfterComment); + } + } else { + if (stringText) { + // Set the text content of the first node after the opening comment, and + // remove all following nodes up until the closing comment. + setTextContent(nodeAfterComment, stringText); + removeDelimitedText(parentNode, nodeAfterComment, closingComment); + } else { + removeDelimitedText(parentNode, openingComment, closingComment); + } + } + + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onHostOperation(ReactDOMComponentTree.getInstanceFromNode(openingComment)._debugID, 'replace text', stringText); + } + } + + var dangerouslyReplaceNodeWithMarkup = Danger.dangerouslyReplaceNodeWithMarkup; + if (process.env.NODE_ENV !== 'production') { + dangerouslyReplaceNodeWithMarkup = function (oldChild, markup, prevInstance) { + Danger.dangerouslyReplaceNodeWithMarkup(oldChild, markup); + if (prevInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onHostOperation(prevInstance._debugID, 'replace with', markup.toString()); + } else { + var nextInstance = ReactDOMComponentTree.getInstanceFromNode(markup.node); + if (nextInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onHostOperation(nextInstance._debugID, 'mount', markup.toString()); + } + } + }; + } + + /** + * Operations for updating with DOM children. + */ + var DOMChildrenOperations = { + + dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup, + + replaceDelimitedText: replaceDelimitedText, + + /** + * Updates a component's children by processing a series of updates. The + * update configurations are each expected to have a `parentNode` property. + * + * @param {array} updates List of update configurations. + * @internal + */ + processUpdates: function (parentNode, updates) { + if (process.env.NODE_ENV !== 'production') { + var parentNodeDebugID = ReactDOMComponentTree.getInstanceFromNode(parentNode)._debugID; + } + + for (var k = 0; k < updates.length; k++) { + var update = updates[k]; + switch (update.type) { + case ReactMultiChildUpdateTypes.INSERT_MARKUP: + insertLazyTreeChildAt(parentNode, update.content, getNodeAfter(parentNode, update.afterNode)); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onHostOperation(parentNodeDebugID, 'insert child', { toIndex: update.toIndex, content: update.content.toString() }); + } + break; + case ReactMultiChildUpdateTypes.MOVE_EXISTING: + moveChild(parentNode, update.fromNode, getNodeAfter(parentNode, update.afterNode)); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onHostOperation(parentNodeDebugID, 'move child', { fromIndex: update.fromIndex, toIndex: update.toIndex }); + } + break; + case ReactMultiChildUpdateTypes.SET_MARKUP: + setInnerHTML(parentNode, update.content); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onHostOperation(parentNodeDebugID, 'replace children', update.content.toString()); + } + break; + case ReactMultiChildUpdateTypes.TEXT_CONTENT: + setTextContent(parentNode, update.content); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onHostOperation(parentNodeDebugID, 'replace text', update.content.toString()); + } + break; + case ReactMultiChildUpdateTypes.REMOVE_NODE: + removeChild(parentNode, update.fromNode); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onHostOperation(parentNodeDebugID, 'remove child', { fromIndex: update.fromIndex }); + } + break; + } + } + } + + }; + + module.exports = DOMChildrenOperations; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 82 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMLazyTree + */ + + 'use strict'; + + var DOMNamespaces = __webpack_require__(83); + var setInnerHTML = __webpack_require__(84); + + var createMicrosoftUnsafeLocalFunction = __webpack_require__(85); + var setTextContent = __webpack_require__(86); + + var ELEMENT_NODE_TYPE = 1; + var DOCUMENT_FRAGMENT_NODE_TYPE = 11; + + /** + * In IE (8-11) and Edge, appending nodes with no children is dramatically + * faster than appending a full subtree, so we essentially queue up the + * .appendChild calls here and apply them so each node is added to its parent + * before any children are added. + * + * In other browsers, doing so is slower or neutral compared to the other order + * (in Firefox, twice as slow) so we only do this inversion in IE. + * + * See https://github.com/spicyj/innerhtml-vs-createelement-vs-clonenode. + */ + var enableLazy = typeof document !== 'undefined' && typeof document.documentMode === 'number' || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && /\bEdge\/\d/.test(navigator.userAgent); + + function insertTreeChildren(tree) { + if (!enableLazy) { + return; + } + var node = tree.node; + var children = tree.children; + if (children.length) { + for (var i = 0; i < children.length; i++) { + insertTreeBefore(node, children[i], null); + } + } else if (tree.html != null) { + setInnerHTML(node, tree.html); + } else if (tree.text != null) { + setTextContent(node, tree.text); + } + } + + var insertTreeBefore = createMicrosoftUnsafeLocalFunction(function (parentNode, tree, referenceNode) { + // DocumentFragments aren't actually part of the DOM after insertion so + // appending children won't update the DOM. We need to ensure the fragment + // is properly populated first, breaking out of our lazy approach for just + // this level. Also, some plugins (like Flash Player) will read + // nodes immediately upon insertion into the DOM, so + // must also be populated prior to insertion into the DOM. + if (tree.node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE || tree.node.nodeType === ELEMENT_NODE_TYPE && tree.node.nodeName.toLowerCase() === 'object' && (tree.node.namespaceURI == null || tree.node.namespaceURI === DOMNamespaces.html)) { + insertTreeChildren(tree); + parentNode.insertBefore(tree.node, referenceNode); + } else { + parentNode.insertBefore(tree.node, referenceNode); + insertTreeChildren(tree); + } + }); + + function replaceChildWithTree(oldNode, newTree) { + oldNode.parentNode.replaceChild(newTree.node, oldNode); + insertTreeChildren(newTree); + } + + function queueChild(parentTree, childTree) { + if (enableLazy) { + parentTree.children.push(childTree); + } else { + parentTree.node.appendChild(childTree.node); + } + } + + function queueHTML(tree, html) { + if (enableLazy) { + tree.html = html; + } else { + setInnerHTML(tree.node, html); + } + } + + function queueText(tree, text) { + if (enableLazy) { + tree.text = text; + } else { + setTextContent(tree.node, text); + } + } + + function toString() { + return this.node.nodeName; + } + + function DOMLazyTree(node) { + return { + node: node, + children: [], + html: null, + text: null, + toString: toString + }; + } + + DOMLazyTree.insertTreeBefore = insertTreeBefore; + DOMLazyTree.replaceChildWithTree = replaceChildWithTree; + DOMLazyTree.queueChild = queueChild; + DOMLazyTree.queueHTML = queueHTML; + DOMLazyTree.queueText = queueText; + + module.exports = DOMLazyTree; + +/***/ }, +/* 83 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMNamespaces + */ + + 'use strict'; + + var DOMNamespaces = { + html: 'http://www.w3.org/1999/xhtml', + mathml: 'http://www.w3.org/1998/Math/MathML', + svg: 'http://www.w3.org/2000/svg' + }; + + module.exports = DOMNamespaces; + +/***/ }, +/* 84 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule setInnerHTML + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(49); + var DOMNamespaces = __webpack_require__(83); + + var WHITESPACE_TEST = /^[ \r\n\t\f]/; + var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/; + + var createMicrosoftUnsafeLocalFunction = __webpack_require__(85); + + // SVG temp container for IE lacking innerHTML + var reusableSVGContainer; + + /** + * Set the innerHTML property of a node, ensuring that whitespace is preserved + * even in IE8. + * + * @param {DOMElement} node + * @param {string} html + * @internal + */ + var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) { + // IE does not have innerHTML for SVG nodes, so instead we inject the + // new markup in a temp node and then move the child nodes across into + // the target node + if (node.namespaceURI === DOMNamespaces.svg && !('innerHTML' in node)) { + reusableSVGContainer = reusableSVGContainer || document.createElement('div'); + reusableSVGContainer.innerHTML = '' + html + ''; + var svgNode = reusableSVGContainer.firstChild; + while (svgNode.firstChild) { + node.appendChild(svgNode.firstChild); + } + } else { + node.innerHTML = html; + } + }); + + if (ExecutionEnvironment.canUseDOM) { + // IE8: When updating a just created node with innerHTML only leading + // whitespace is removed. When updating an existing node with innerHTML + // whitespace in root TextNodes is also collapsed. + // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html + + // Feature detection; only IE8 is known to behave improperly like this. + var testElement = document.createElement('div'); + testElement.innerHTML = ' '; + if (testElement.innerHTML === '') { + setInnerHTML = function (node, html) { + // Magic theory: IE8 supposedly differentiates between added and updated + // nodes when processing innerHTML, innerHTML on updated nodes suffers + // from worse whitespace behavior. Re-adding a node like this triggers + // the initial and more favorable whitespace behavior. + // TODO: What to do on a detached node? + if (node.parentNode) { + node.parentNode.replaceChild(node, node); + } + + // We also implement a workaround for non-visible tags disappearing into + // thin air on IE8, this only happens if there is no visible text + // in-front of the non-visible tags. Piggyback on the whitespace fix + // and simply check if any non-visible tags appear in the source. + if (WHITESPACE_TEST.test(html) || html[0] === '<' && NONVISIBLE_TEST.test(html)) { + // Recover leading whitespace by temporarily prepending any character. + // \uFEFF has the potential advantage of being zero-width/invisible. + // UglifyJS drops U+FEFF chars when parsing, so use String.fromCharCode + // in hopes that this is preserved even if "\uFEFF" is transformed to + // the actual Unicode character (by Babel, for example). + // https://github.com/mishoo/UglifyJS2/blob/v2.4.20/lib/parse.js#L216 + node.innerHTML = String.fromCharCode(0xFEFF) + html; + + // deleteData leaves an empty `TextNode` which offsets the index of all + // children. Definitely want to avoid this. + var textNode = node.firstChild; + if (textNode.data.length === 1) { + node.removeChild(textNode); + } else { + textNode.deleteData(0, 1); + } + } else { + node.innerHTML = html; + } + }; + } + testElement = null; + } + + module.exports = setInnerHTML; + +/***/ }, +/* 85 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule createMicrosoftUnsafeLocalFunction + */ + + /* globals MSApp */ + + 'use strict'; + + /** + * Create a function which has 'unsafe' privileges (required by windows8 apps) + */ + + var createMicrosoftUnsafeLocalFunction = function (func) { + if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { + return function (arg0, arg1, arg2, arg3) { + MSApp.execUnsafeLocalFunction(function () { + return func(arg0, arg1, arg2, arg3); + }); + }; + } else { + return func; + } + }; + + module.exports = createMicrosoftUnsafeLocalFunction; + +/***/ }, +/* 86 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule setTextContent + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(49); + var escapeTextContentForBrowser = __webpack_require__(87); + var setInnerHTML = __webpack_require__(84); + + /** + * Set the textContent property of a node, ensuring that whitespace is preserved + * even in IE8. innerText is a poor substitute for textContent and, among many + * issues, inserts
instead of the literal newline chars. innerHTML behaves + * as it should. + * + * @param {DOMElement} node + * @param {string} text + * @internal + */ + var setTextContent = function (node, text) { + if (text) { + var firstChild = node.firstChild; + + if (firstChild && firstChild === node.lastChild && firstChild.nodeType === 3) { + firstChild.nodeValue = text; + return; + } + } + node.textContent = text; + }; + + if (ExecutionEnvironment.canUseDOM) { + if (!('textContent' in document.documentElement)) { + setTextContent = function (node, text) { + setInnerHTML(node, escapeTextContentForBrowser(text)); + }; + } + } + + module.exports = setTextContent; + +/***/ }, +/* 87 */ +/***/ function(module, exports) { + + /** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * Based on the escape-html library, which is used under the MIT License below: + * + * Copyright (c) 2012-2013 TJ Holowaychuk + * Copyright (c) 2015 Andreas Lubbe + * Copyright (c) 2015 Tiancheng "Timothy" Gu + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * @providesModule escapeTextContentForBrowser + */ + + 'use strict'; + + // code copied and modified from escape-html + /** + * Module variables. + * @private + */ + + var matchHtmlRegExp = /["'&<>]/; + + /** + * Escape special characters in the given string of html. + * + * @param {string} string The string to escape for inserting into HTML + * @return {string} + * @public + */ + + function escapeHtml(string) { + var str = '' + string; + var match = matchHtmlRegExp.exec(str); + + if (!match) { + return str; + } + + var escape; + var html = ''; + var index = 0; + var lastIndex = 0; + + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: + // " + escape = '"'; + break; + case 38: + // & + escape = '&'; + break; + case 39: + // ' + escape = '''; // modified from escape-html; used to be ''' + break; + case 60: + // < + escape = '<'; + break; + case 62: + // > + escape = '>'; + break; + default: + continue; + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + + lastIndex = index + 1; + html += escape; + } + + return lastIndex !== index ? html + str.substring(lastIndex, index) : html; + } + // end code copied and modified from escape-html + + + /** + * Escapes text to prevent scripting attacks. + * + * @param {*} text Text value to escape. + * @return {string} An escaped string. + */ + function escapeTextContentForBrowser(text) { + if (typeof text === 'boolean' || typeof text === 'number') { + // this shortcircuit helps perf for types that we know will never have + // special characters, especially given that this function is used often + // for numeric dom ids. + return '' + text; + } + return escapeHtml(text); + } + + module.exports = escapeTextContentForBrowser; + +/***/ }, +/* 88 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Danger + */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(7); + + var DOMLazyTree = __webpack_require__(82); + var ExecutionEnvironment = __webpack_require__(49); + + var createNodesFromMarkup = __webpack_require__(89); + var emptyFunction = __webpack_require__(12); + var invariant = __webpack_require__(8); + + var Danger = { + + /** + * Replaces a node with a string of markup at its current position within its + * parent. The markup must render into a single root node. + * + * @param {DOMElement} oldChild Child node to replace. + * @param {string} markup Markup to render in place of the child node. + * @internal + */ + dangerouslyReplaceNodeWithMarkup: function (oldChild, markup) { + !ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString() for server rendering.') : _prodInvariant('56') : void 0; + !markup ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : _prodInvariant('57') : void 0; + !(oldChild.nodeName !== 'HTML') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the node. This is because browser quirks make this unreliable and/or slow. If you want to render to the root you must use server rendering. See ReactDOMServer.renderToString().') : _prodInvariant('58') : void 0; + + if (typeof markup === 'string') { + var newChild = createNodesFromMarkup(markup, emptyFunction)[0]; + oldChild.parentNode.replaceChild(newChild, oldChild); + } else { + DOMLazyTree.replaceChildWithTree(oldChild, markup); + } + } + + }; + + module.exports = Danger; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 89 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {'use strict'; + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @typechecks + */ + + /*eslint-disable fb-www/unsafe-html*/ + + var ExecutionEnvironment = __webpack_require__(49); + + var createArrayFromMixed = __webpack_require__(90); + var getMarkupWrap = __webpack_require__(91); + var invariant = __webpack_require__(8); + + /** + * Dummy container used to render all markup. + */ + var dummyNode = ExecutionEnvironment.canUseDOM ? document.createElement('div') : null; + + /** + * Pattern used by `getNodeName`. + */ + var nodeNamePattern = /^\s*<(\w+)/; + + /** + * Extracts the `nodeName` of the first element in a string of markup. + * + * @param {string} markup String of markup. + * @return {?string} Node name of the supplied markup. + */ + function getNodeName(markup) { + var nodeNameMatch = markup.match(nodeNamePattern); + return nodeNameMatch && nodeNameMatch[1].toLowerCase(); + } + + /** + * Creates an array containing the nodes rendered from the supplied markup. The + * optionally supplied `handleScript` function will be invoked once for each + * + + diff --git a/tests/react-web/package.json b/tests/react-web/package.json new file mode 100644 index 00000000..60ddf8c2 --- /dev/null +++ b/tests/react-web/package.json @@ -0,0 +1,44 @@ +{ + "name": "testing", + "version": "1.0.0", + "description": "testing React with Jest", + "main": "index.js", + "scripts": { + "watch": "webpack -w", + "start": "live-server --port=8081", + "pretest": "npm install", + "test": "./node_modules/.bin/jest --env=jsdom" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^0.16.2", + "react": "15.3.2", + "react-dom": "15.3.2", + "rxjs": "^5.4.3", + "shortid": "2.2.6", + "babel-core": "6.14.0", + "babel-jest": "16.0.0", + "babel-loader": "6.2.5", + "babel-polyfill": "6.16.0", + "babel-preset-es2015": "6.16.0", + "babel-preset-react": "6.16.0", + "babel-preset-stage-0": "^6.24.1", + "enzyme": "2.4.1", + "jest": "16.0.0", + "react-addons-test-utils": "15.3.2", + "react-test-renderer": "15.3.2", + "webpack": "1.13.2" + }, + "devDependencies": { + "live-server": "1.1.0" + }, + "babel": { + "presets": [ + "es2015", + "react", + "stage-0" + ] + } +} diff --git a/tests/react-web/webpack.config.js b/tests/react-web/webpack.config.js new file mode 100644 index 00000000..d3ab404a --- /dev/null +++ b/tests/react-web/webpack.config.js @@ -0,0 +1,13 @@ +module.exports = { + entry: './app/index.js', + output: { + filename: 'bundle.js' + }, + module: { + loaders: [{ + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel' + }] + } +}